zoukankan      html  css  js  c++  java
  • 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]# 
  • 相关阅读:
    删除数据库的数据后让id从1开始算
    通过数据库绑定的dropdownlist,如何让其第一条默认显示"--请选择--"
    winform 验证用户正确后打开新窗口时关闭登陆窗口
    winform FormBordStyle=none 及 wpf FormBordStyle=none 的鼠标点击移动问题
    [AngularJS] AngularJS系列(3) 中级篇之表单验证
    linux开启mysql远程登录
    linux下JDK,tomcat的安装与环境变量配置
    linux下mysql连接jar包的位置在哪里?
    linux下mysql忘记root密码的解决方案
    RedHat下MySQL 5.6 安装、维护
  • 原文地址:https://www.cnblogs.com/neozheng/p/11148974.html
Copyright © 2011-2022 走看看