Post

golang

go简介

  • 静态类型
  • 运行是runtime

基础题

  • https://learnku.com/articles/35063

规范

  • 相似的变量放在一起声明
  • import包顺序,标准库、第三方库
  • 包名全部小写
  • map、slice初始化
  • 枚举从1开始
  • 可以指定slice的容量

变量类型

  • 值类型:array、int、struct
  • 引用类型:map、slice、channel、指针、interface、函数

类型比较

  • 可比较:int、float、string、bool、pointe、channel、interface、array
  • 不可比较(编译报错):slice、map、func
  • 复合类型含有不可比较的类型,则该类型也是不可比较;如struct
    • struct含有不可比较类型时,可用reflect.DeepEqual比较
  • 浅析go中的类型比较:https://segmentfault.com/a/1190000039005467

优点

  • 编译快
  • 执行效率高
  • 内存管理GC
  • 海量并发

缺点

  • 第三方库不够多、不够稳定
  • 错误处理代码冗余

struct值接收者和指针接收者

  • 值类型调用者、指针类型调用均可调用值接受者和指针接收者定义的方法

  • 指针接收者可以修改调用方的值,而值类型接收者不可以

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    
    type Student struct {
        Name string
    }
      
    // 修改调用方的值
    func (s *Student) SetName() {
        s.Name = "point name"
    }
      
    // 不可修改调用方的值
    func (s Student) SetName2() {
        s.Name = "object name"
    }
      
    func TestSetName(t *testing.T) {
        // 值对象
        stu := Student{
            Name: "zeyuan.li",
        }
      
        stu.SetName()
        t.Log(stu.Name) // point name
        stu.SetName2()
        t.Log(stu.Name) // point name
      
        // 指针对象
        stu2 := &Student{
            Name: "ahern",
        }
      
        stu2.SetName()
        t.Log(stu2.Name) // point name
        stu2.SetName2()
        t.Log(stu2.Name) // point name
    }
    
  • 当有定义接口,接收者为指针时,值类型的调用者不能赋给该接口

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    
    type People interface {
        Say() 
    }
      
    type Student struct {
        Name string
    }
      
    func (stu *Student) Say()  {
        fmt.Println("say name: ", stu.Name)
        return 
    }
      
    func Test36(t *testing.T) {
        var p People
        stu := Student{"d"}
        p = stu // 编译报错
        p.Say()
    }
    

iota

不同 const 定义块互不干扰(遇到const会重置成0)
1
2
3
4
5
6
7
8
9
func Test40(t *testing.T) {
    const a = iota

    const (
        b = iota
    )
    fmt.Println(a) // 0
    fmt.Println(b) // 0
}
非空行则加一
  • 从第一行开始,iota 从 0 逐行加一
  • 没有表达式的常量定义复用上一行的表达式
  • 同一行,iota值相等
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
func Test41(t *testing.T) {
    const (
        c    = 10                        // iota:0; 输出:10; 从第一行开始,iota 从 0 逐行加一
        d    = iota                      // iota:1; 输出:1
        e                                // iota:2; 输出:2; 没有表达式的常量定义复用上一行的表达式
        f    = "hello"                   // iota:3; 输出:hello
        g                                // iota:4; 输出:hello
        h    = iota                      // iota:5; 输出:5
        i                                // iota:6; 输出:6
        j    = 0                         // iota:7; 输出:0
        k                                // iota:8; 输出:0
        l, m = iota, iota                // iota:9; 输出:9, 9; 同一行,iota值相等
        n, o                             // iota:10; 输出:10, 10
        p    = iota + 1                  // iota:11; 输出:11 + 1
        q                                // iota:12; 输出:12 + 1
        _                                // iota:13; 输出:
        r    = iota * iota               // iota:14; 输出:14 * 14
        s                                // iota:15; 输出:15 * 15
        tt   = r                         // iota:16; 输出:196
        u                                // iota:17; 输出:196
        v    = 1 << iota                 // iota:18; 输出:1 << 18
        w                                // iota:19; 输出:1 << 19
        x                  = iota * 0.01 // iota:20; 输出:20 * 0.01
        y    float32       = iota * 0.01 // iota:21; 输出:21 * 0.01
        z                                // iota:22; 输出:22 * 0.01
    )

    fmt.Println(c)  
    fmt.Println(d)  
    fmt.Println(e)  
    fmt.Println(f)  
    fmt.Println(g)  
    fmt.Println(h)  
    fmt.Println(i)  
    fmt.Println(j)  
    fmt.Println(k)  
    fmt.Println(l)  
    fmt.Println(m)  
    fmt.Println(n)  
    fmt.Println(o)  
    fmt.Println(p)  
    fmt.Println(q)  
    fmt.Println(r)  
    fmt.Println(s)  
    fmt.Println(tt) 
    fmt.Println(u)  
    fmt.Println(v)  
    fmt.Println(w)  
    fmt.Println(x)  
    fmt.Println(y)  
    fmt.Println(z)  
}

for循环

  • 三种形式:for、for+赋值、for+range

  • 支持continue、break等操作

  • 1
    2
    3
    4
    5
    6
    7
    
    func TestFor(t *testing.T) {
        ...
        for i, v := range l {
            ...
        }
        ...
    }
    
    • i、v是同一块内存

for-range

  • 新版本Go,for _, v := range slice,v为不同内存地址

  • 一边遍历slice,一边append元素到slice,会停止遍历

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    func TestForAppend(t *testing.T) {
        arr := []int{1, 2}
        res := []int{}
        for _, v := range arr {
            res = append(res, v)
            arr = append(arr, v)
        }
        fmt.Println(arr) // [1 2 1 2]
        fmt.Println(res) // [1 2]
    }
    
  • 对map遍历时新增元素能遍历到么?【可能会】

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    var m = map[int]int{1:1, 2:2, 3:3}
    for i, _ := range m {
        m[4] = 4
        fmt.Printf("%d%d ", i, m[i])
    }
      
    /*
    map内部是hash链表实现,为保证遍历无序,初始化时,会随机从一个位置开始
    */
    
  • https://zhuanlan.zhihu.com/p/105435646

控制goroutine数量

  • 1、chan
  • 2、sync.WaitGroup
  • 3、协程池(chan + sync)

goroutine泄露场景

  • 1、goroutine无限阻塞等待
  • 2、goroutine死循环

参考

  • https://segmentfault.com/a/1190000022285902
This post is licensed under CC BY 4.0 by the author.