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.