golang(1):简介

golang语言特性:

1. 垃圾回收
    a. 内存自动回收,不需要开发人员管理内存,开发人员专注业务实现
    b. 只需要new分配内存,不需要释放
    
2. 天然并发
    a. 从语言层面支持并发,非常简单
    b. goroute,轻量级线程,使创建成千上万个 goroute 成为可能
    c. 基于CSP(Communicating Sequential Process)模型实现
    
3. channel (管道)
    a. 管道,类似 unix/linux 中的 pipe
    b. 多个 goroutine 之间通过 channel 进行通信
    c. 支持任何类型
    
// 示例:
func main() {
    pipe := make(chan int,3)    # pipe := make(chan int,3) 做了两件事:1.声明一个管道变量pipe,pipe为int,2. 为管道pipe分配了一个新的内存空间;make 是一个关键字,表示分配一个内存空间;chan 也是一个关键字,说明该参数是个管道;3表示管道的容量,指定这个管道中最多只能放3个int
    pipe <- 1        # 表示把 1 放到管道pipe中
    pipe <- 2        # 表示把 2 放到管道pipe中
}

4. 多返回值
    a. 一个函数 返回多个值

func calc(a int,b int) (int,int){    // 两个以上的返回值要放到 () 中
    sum := a + b
    avg := (a+b)/2
    return sum,avg
}

 

第一个go程序: helloworld.go

package main     
// go每一个文件都属于一个包;package 关键字说明这个文件是一个包;想让这个包成为一个可执行文件,包名必须为 main 

// 导入输出的包
import(        
    "fmt"
)

// go 语言的代码被编译时,每行最后会自动加一个 “;”

// 定义变量a 为整型,变量b为整型;规定返回值 也是 整型
func add(a int,b int) int {
    var sum int     // 定义一个变量 sum 为整型
    sum = a + b
    return sum
}

// go 代码执行的时候会从 main 函数开始执行; main 是入口函数
func main(){
    var c int
    c = add(100,200)    // 定义的变量 c 必须有被引用才能通过编译
    fmt.Println("add(100,200)=", c)

    fmt.Println("hello world")
}
test_goroutine 测试程序:

helloworld.go

package main     


import(        
    "time"        // 导入时间函数
)

func main() {
    for i := 0; i < 100; i++ {        // sum := a +b    // sum :=  这种定义变量的方式会根据 = 后面的变量 自动把 sum 定义成 int 整型
        // 调用 test_goroutine 函数
        go test_goroutine(i)        // test_goroutine 函数和  main 函数 都在 main 这同一个包里面,此时包名可以省略
        // go test_goroutine(i) 是并发运行的
    }
    
    // 主函数运行在一个 goroute 里面,然后又起了100个test_goroutine;主线程这个 test_goroutine 要等待 那100个子线程执行完
    time.Sleep(time.Second)        // sleep 1 秒
}

test.go

package main    
// test.go 文件也是在 main 这个包里面

import (
    "fmt"
)

func test_goroutine(a int) {
    fmt.Println(a)
}

终端显示如图:

管道 channel 示例1:

main.go

package main

func main()  {
    test_pipe()
}

pipe.go

package main

import (
    "fmt"
)

func test_pipe(){
    pipe := make(chan int, 3)
    pipe <- 1
    pipe <- 2
    pipe <- 3 

    fmt.Println(len(pipe))        // len(pipe)  --->  管道的长度; 管道满了后,再往管道中放 值,管道会 pend住,直到管道中有值被取出,pend住的值才会放入到管道中

    var t1 int
    t1 =<- pipe   // 从管道中取出一个值
    fmt.Println(t1)

}

管道 channel 示例2: 通过传参的方式,利用 管道进行 goroutine 之间的通讯

package main

import (
    "fmt"
    "time"
)

func add(a int,b int,c chan int) {  // c chan int  ---> 形参 c 是一个int 类型的管道
    var sum int
    sum = a + b 

    time.Sleep(3*time.Second)      //  sleep 3 秒
    c <- sum                        // 把 sum 放到管道 c 中
}


func main(){
    var pipe chan int           // 声明一个变量 pipe 为int 的管道
    pipe = make(chan int,1)       // 为管道pipe分配一个新的内存空间; pipe 的容量大小为1

    go add(2,5,pipe)             // 开启一个新的 goroutine;把 pipe当作参数传入 add函数中

    sum :=<- pipe                  // 从管道pipe 中取值,并赋值给类型为int的变量sum;通过这种方式主线程就能获取到 add 这个子线程中的值; 虽然 add 中 会 sleep 3 秒,但这行代码下面不需要再 sleep,因为当 add 没执行完的时候, 管道 pipe中没有值,此时程序会 pend在这行代码处
    fmt.Println("sum=",sum)

    // time.Sleep(10*time.Second)        // 此处不需要再 sleep 10 秒来等待子线程执行完毕
}

函数多返回值示例:

package main

import (
    "fmt"
)

func calc(a int,b int) (int, int){
    sum := a + b
    avg := (a+b)/2
    return sum, avg
}

func main(){
    sum, avg := calc(100,200)        // 取出返回值
    // sum, _ := calc(100, 320)        // 只取一个返回值的写法

    fmt.Println("sum=",sum,"avg=",avg)
}

 

包的概念:

1. 和 python 一样,把相同功能的代码放到一个目录,称之为包;包 和 文件夹 是对应的
2. 包可以被其他包引用
3. main 包是用来生成可执行文件,第个程序只有一个 main 包
4. 包的主机用途是提高代码的可利用性

// go 语言中 所有的代码文件的都是以包的形式存在的,没有哪个代码文件不属于任何一个包

测试项目目录结构如下:

[root@NEO ~]# echo $GOPATH    
/root/go/project        // $GOPATH 的目录


[root@NEO project]# tree /root/go/project/
/root/go/project/
├── bin
├── example01
├── pkg
├── src
│   └── go_dev
│       └── day01
│           ├── example01
│           │   └── hello.go
│           └── package_example
│               ├── calc
│               │   ├── add.go
│               │   └── sub.go
│               └── main
│                   └── main.go
└── vender

10 directories, 5 files
[root@NEO project]#

example01 包的代码如下:

package main

import (
    "fmt"
)

func main(){
    fmt.Println("hello world")
}

编译 go_dev/day01/example01/ 包的命令:

[root@NEO project]# go build go_dev/day01/example01
[root@NEO project]# ll
total 1968
drwxr-xr-x 2 root root    4096 Jul  9 17:44 bin
-rwxr-xr-x 1 root root 1997487 Jul 10 01:47 example01     // 编译后生成的可执行文件     
drwxr-xr-x 2 root root    4096 Jul  9 17:44 pkg
drwxr-xr-x 3 root root    4096 Jul  9 17:44 src
drwxr-xr-x 2 root root    4096 Jul  9 17:44 vender
[root@NEO project]# ./example01 
hello world
[root@NEO project]#

 

包测试项目 package_example示例:

package_example/main/main.go 的代码如下:

package main

import (
    // 从 src 目录下开始导入包
    "go_dev/day01/package_example/calc"        
    "fmt"
)

// go build 的时候不用写 src 目录,因为 go 在编译的时候默认会从 src 目录下开始找

func main(){
    sum := calc.Add(100,300)
    sub := calc.Sub(100,300)

    fmt.Println("sum=",sum)
    fmt.Println("sub=",sub)
}

// go build 时,先在命令行切到 /project 目录; 同时从根目录到 /project 的路径要添加到 环境变量 GOPATH 中
// go build -o bin/main.exe go_dev/day01/package_example/main
    // -o 参数表示编译包生成的位置; go_dev/day01/package_example/main 表示编译哪个包 (路径最前面不要加 /)
    // 执行上面的命令后会在 bin 目录下生成 main.exe 可执行文件

// windowns 环境下的代码

package_example/calc/add.go 代码如下:

package calc


// 可导出的函数,首字母必须大写
func Add(a int,b int) int {
    return a +b 
}

// windows环境下的代码

package_example/calc/sub.go 代码如下:

package calc


// 可导出的函数,首字母必须大写
func Add(a int,b int) int {
    return a +b 
}

// windows 环境下的代码

在linux环境下编译该项目:

[root@NEO project]# go build -o bin/main go_dev/day01/package_example/main  // 编译的命令
[root@NEO project]# ll bin/
total 1952
-rwxr-xr-x 1 root root 1997628 Jul 10 02:05 main
[root@NEO project]# ./bin/main 
sum= 400
sub= -200
[root@NEO project]# 

 

posted @ 2019-07-08 01:36  neozheng  阅读(490)  评论(0编辑  收藏  举报