go

THZXQ · · 656 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

语言简介

go是强类型静态语言,也就是说在编译阶段就确定变量类型,并且转换类型需要显示转换,它有如下几个特点:
  1. 跟脚本语言相似,容易上手、容易流行
  2. 底层是c,性能好
  3. 对goroutine调度进行了封装,即在语言层面支持协程,对于开发者,用起来方便

编译过程

  • go以包的形式管理源程序,每个包至少包含一个go文件。编译的时候会把main包生成可执行文件放到bin目录下,其他包生成xx.a包文件放到pkg目录下。

可执行程序初始化过程

  • 先执行main包的go文件,对依赖的包递归执行import、常量和变量初始化、init函数流程之后,初始化main自己的常量和变量、再依次执行init函数和main函数,示意图如下(竟然不能直接放图片,😳):
    https://github.com/JJAWX/imag...

go文件基本构成

package xx

表明这个go文件是属于哪个包,这条语句是必须写的,因为go是以package的形式管理源文件的

import xx

引入当前文件依赖的包,包的路径只可以是相对路径,eg:"xxx/decorator",go查找包的过程是先在$GOROOT/src($GOROOT是go的安装路径,默认在/usr/local/go下)文件夹下找,如果找不到就从$GOPATH/src($GOPATH是go工作空间路径,当前工作代码所在的go文件夹路径)文件下找。

var/const声明初始化

整型
    var test int = 123
布尔
    var test bool = true
字符串
    var test string = "abc"
数组(数组必须指定长度,否则属于切片,不赋值,指定长度默认[0,0])
    var test [2]int
    test[0] = 6
    test[1] = 8
切片(没指定长度的数组或者用make初始化的数组)
    // 添加元素方式一
    var test = make([]string, 0)
    test = append(test, 2)
    // 添加元素方式二
    var test = make([]string, 2)
    test[0] = "123"
    test[1] = "456"
结构体
    type TestA struct {
        c int
    }
    type Test struct {
        a int
        b string
        c int
        TestA
    }
    var test = Test{6, "aa", 8, TestA{3}} // 或者不初始化:var test Test
channel
    test := make(chan int)
    go func(){ test <- 1 }()
    fmt.Printf("aaa: %+v", <-test)
interface{}(一个接口可以拥有任何实现了它所有方法的类型的属性,空接口代表所有对象都实现了它,也就是说用它可以接收任何类型)
    type Test interface{
        Say()
    }
    type TestA struct{}
    func (a TestA) Say(){
        fmt.Printf("hello")

    } 
    var testa TestA
    var test Test
    test = testa // 接口类型,
指针
     var  testPtr *int // 定义了没有分配到任何变量时,为空指针
map(默认是nil,不初始化,不能存任何东西)
    // 方式一
    var test = make(map[string]string)
    test["a"] = "123"
    
    // 方式二
    var test = map[string]string{}
    test["a"] = "123"
    
    // 方式三
    test := make(map[string]string)
    test["a"] = "123"

init函数

初始化一些全局变量,供所属包或者所有包调用

main函数

属于main包,是程序的入口,和main包是一一对应的关系。

其他函数

业务子逻辑,处理客户端的GET、POST、PUT、DELETE等请求,get请求使用url库对请求参数进行解析,跟它相关的几个方法是:DefaultQuery、Query、QueryArray,;GET、POST、PUT、DELETE请求的话使用的是gin框架的model binding模型,相关的几个方法是:BindWith、BindJSON、Bind、它们底层都使用了MustBindWith这个方法, 这个方法接收两个参数,一个是要解析的struct(ps:解析的对象必须是struct或者是指向struct的指针),另一个是binding,由跟Bind相关的几个函数指定,指定的方式区别如下:

  • BindWith: 可接收两个参数,一个是要解析的对象,一个是binding
  • BindJSON: 只接收一个参数,是要解析的对象,使用的binding是bing.JSON,它对要解析的数据是怎么处理的呢,从req.body中拿出要解析的数据,使用reflect反射对要解析的对象类型进行判断,然后从req.body中取要的数据
  • Bind: 接收一个参数,会根据请求的method和content-type判断使用什么binding来解决。

逻辑处理完成,需要使用context.JSON(关键:json.Marshal)或context.HTML(ps: 分别接收三个参数:状态码、模版路径、模版数据)将结果返回给客户端。

go异常捕捉处理

和异常处理相关的几个关键字:defer(return的时候执行)、recover(捕捉异常)、panic(err)(抛出异常),需要注意的地方是如果子协程不捕捉处理异常,就会报到主线程,由主线程处理,但是子协程会异常退出。

    func example () {
        defer func() {
            if err := recover(); err != nil {
                fmt.Printf("error: %+v", err)
            } else {
                fmt.Printf("抛出了一个nil")
            }
        }()
        // panic(nil) // 结果:抛出了一个nil
        panic("fail") // 结果: error: failed
    }

go并发

go关键字 + channel

    // 无缓冲通道
    func example () {
        test := make(chan int)
        go func(){
            test <- 1
        }()
        fmt.Printf("channel value: %+v", <-test)
    }
    // 执行结果
    channel value: 1
    
    // 缓冲通道
    func example () {
        test := make(chan int, 2)
        go func(){
            for i := 0; i < 2; i++ {
                test <- i
            }
            close(test) // 很重要,需要手动关闭,要不然会造成死锁
        }()
        for ch := range test {
            fmt.Printf("channel value: %+v", ch)
            fmt.Println("")
        }
    }
    // 执行结果
    channel value: 0
    channel value: 1

sync.WaitGroup(例子 + 结果)

    func example () {
        var wg sync.WaitGroup
        for i := 0; i < 2; i++ {
            m := i // 考虑到主线程释放控制权之后协程才执行,缓存i
            wg.Add(1)
            go func(){
                defer func(){
                    fmt.Println("ending...")
                    wg.Done()
                }()
                fmt.Println(fmt.Sprintf("当前循环到哪里了: %+v", m))
            }()
        }
        
        fmt.Println("example...")
        wg.Wait()
    }
    // 执行结果
    example...
    当前循环到哪里了: 0
    ending...
    当前循环到哪里了: 1
    ending...

欢迎关注我们的微信公众号,每天学习Go知识

本文来自:Segmentfault

感谢作者:THZXQ

查看原文:go

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:731990104

656 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传