Go 语言新手笔记(二)
Go 语方的数组声明方式别具一格,把 [] 看得太重了,看下面的各种声明方式
再次强调 Go 的数组是值类型,作为函数参数传递会产生副本。避免传入数组产生副本消耗过多内存,办法是可传数组指针或用切片,切片是第一选择。
数组的大小最大为 2GB,用
切片(slice) 是对数组的一个连续片断引用, 切片的各种创建方式
切片相对于数组有些像数据库的视图与数组的关系。切片的一个基本操作 append(),超出容量时会指向新的数组。
map 的基本声明和操作
type 定义类型或别名的用法Go 的函数也是一种类型,与函数的签名一致,有点像 C/C++ 的函数指针一样
Go 的错误处理类型是 error, Go 居然没有像多数现代语言那样的 try/catch 方式,而是通常函数在有错误的时候额外返回一个 error
个人不太喜欢这种异常的处理方法,看看 panic, differ 和 recover。下面是 panic, recover 和 differ 的用法, 以及理解它们是怎么工作的
输出
好像有了 try/catch 的影子了。recover() 函数只能在有 defer 修饰的函数中使用,用于取得异常传递来的错误信息,没错的话它返回 nil.
panic(): 严重不可恢复,recover(): 从异常或错误中恢复,defer 延迟
Go 也可以像 JavsScript 那样定义一个函数并立即执行它
defer 在 Go 语言中还是比较新鲜的东西,又有一种 finally 的味道,defer 的三个规则
输出为 hello world !!!
输出为 10,return 语句相当于是 ret = xxx -> 调用 defer() -> return ret
函数的定义格式为 func functionName(a typea, b typeb)(r1 type1, r2 type2), 具体会有以下几种形式
Go 的函数不允许重载,Go 默认按值传递,传入的参数会先产生一个副本。要能修改参数值的话需传入一个地址,这时候函数及调用方式为
这是不是和 C/C++ 的指针一样的!
Go 的内置函数 make(T) 和 new(T)
其他的一些内置函数,len(), cap(), append(), copy(), delete(), close(), complex(), real(), image(), panic(), recover(), print(), println()
Go 的匿名函数也称为闭包,闭包对变量的捕获相当于引用传递,即不不会产生副本。可以修改外层的变量
对变参函数的调用,传入多个值,切片时要打散传入, 数组必须转换成 slice, 再打算传入
Go 对新建的 array 或 slice 可以立即取值,但不能立即由新建的 array 得到一个 slice
永久链接 https://yanbin.blog/go-language-notes-2/, 来自 隔叶黄莺 Yanbin's Blog
[版权声明]
本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。
1var a = [...]int{18, 20} // 这是一个数组,如果省略 ..., 写成 []int{18, 20} 就是一个 slice
2var b = [5]string{"hello", 3: "ok"} //指定位置初始化
3var c = [...]float32{2.0, 2.3} // ... 可省略
4var d [20]int // d 的类型是 [20]int
5var e = new([20]int) // e 的类型是 *[20]int, 这是一个数组指针
6var g = [2][2][2]float64 // 多维数组
7var h = [...][5]int{{10,20}, {30,40}} // 类似其他语言一样,只有第一维才能用 [...]数组的大小最大为 2GB,用
== 或 != 比较两个数组时它们必须类型和长度一致。切片(slice) 是对数组的一个连续片断引用, 切片的各种创建方式
1var arr = [...]int{2,3,5,6,8,4} // 初始一个数组
2var s1 []int // 创建新切片
3
4fmt.Println(s1, s1==nil, len(s1)) // [] true 0
5fmt.Println(reflect.TypeOf(arr), reflect.TypeOf(s1)) // [6]int []int
6
7var s2 = arr[2:4] // 新建切片指定数组 arr 的索引从 2 到 4 的元素
8var s3 = []int{1,2,3}
9var s4 = make([]int, 2, 5) // 分配一个长度为 5 的数组,并创建容量为 2 的 slice 指向前 2 个元素
10var s5 = s3[0:2] // 从切片生成新的切片, 可简写为 s3[:2]
11var s6 = arr[2:4:5] //a[low:high:max], 长度为 high-low, 容量为 max-lowmap 的基本声明和操作
1var map1 map[string]int // 空 map
2map2 := make(map[string]int) // 用 make 创建 map
3var map3 = make(map[string]int, 10) // 指定容量为 10
4var map4 = map[string]int{"a": 1, "b": 2}
5
6fmt.Println(map4["a"]) // 读取元素
7map4["c"] = 3 // 添加元素
8fmt.Println(map4)
9delete(map4, "a") // 删除元素
10
11for key, val := range map4 { // for..range 遍历
12 fmt.Println(key, val)
13} 1type IZ int // 定义新类型
2var a IZ = 5
3fmt.Println(reflect.TypeOf(a), a)
4
5var b int = int(a) // 必须显式转型
6
7type (
8 FZ float64 // 新型 FZ 没有 float64 的相应方法
9 STR string
10)
11
12type B = byte // 类型别名定义,B 和 byte 就是完全一样的了1func foo(a int, b int) int {
2 return a + b
3}
4
5func main() {
6 type barFun func(int, int) int
7 var f1 barFun = foo
8 fmt.Println(f1(3, 3))
9} 1func foo(a int) (x int, err error) {
2 if a > 1 {
3 return 0, errors.New("greater than 1")
4 } else if a < 0 {
5 return 0, fmt.Errorf("smaller than zero %d", a)
6 }
7 return a + 1, nil
8}
9func main() {
10 val, err := foo(2)
11 if err != nil {
12 fmt.Println(val)
13 }
14} 1func div(a, b int) {
2 defer func() {
3 if r:=recover(); r!=nil {
4 fmt.Printf("caught error: %s\n", r)
5 }
6 }() // 这时定义并调用了 defer 函数, 所以可用 defer 来执行一个函数,如 defer fmt.Println("xx")
7
8 if b < 0 {
9 panic("not negative") // panic() 会调用到 defer 函数
10 }
11
12 fmt.Println("result: ", a/b) // a/b 有异常时也会调用 defer 函数
13}
14
15func div1(a, b int) { // 测试函数中没有定义 defer 函数的情况
16 fmt.Println("result: ", a/b)
17}
18
19func main() {
20 div(10, 0) // caught error: runtime error: integer divide by zero
21 div(10, -1) // caught error: not negative
22 div1(10, 0) // panic: runtime error: integer divide by zero
23}caught error: runtime error: integer divide by zero
caught error: not negative
panic: runtime error: integer divide by zero goroutine 1 [running]:
main.div1(...)
/Users/yanbin/Workspaces/tests/test-go/src/test.go:22
main.main()
/Users/yanbin/Workspaces/tests/test-go/src/test.go:29 +0x4f
好像有了 try/catch 的影子了。recover() 函数只能在有 defer 修饰的函数中使用,用于取得异常传递来的错误信息,没错的话它返回 nil.
panic(): 严重不可恢复,recover(): 从异常或错误中恢复,defer 延迟
Go 也可以像 JavsScript 那样定义一个函数并立即执行它
1func main() {
2 func(a, b int) {
3 fmt.Println("result: ", a+b)
4 }(4, 5)
5}- defer 声明时其后面函数参数被实时解析
- defer 执行顺序为先进后出 (FILO)
- defer 可读取函数的有名返回值
1func main() {
2 i := 2
3 defer fmt.Println(func() int { return i * 2 }())
4 // 相当于 defer fmt.Println(fun() int {return 4}())
5
6 i++
7}1func main() {
2 defer fmt.Print(" !!!")
3 defer fmt.Print(" world")
4 defer fmt.Print("hello")
5} 1func foo() (i int) {
2 defer func() {
3 i += 10
4 }()
5 return 0
6}
7
8func main() {
9 fmt.Println(foo())
10}函数的定义格式为 func functionName(a typea, b typeb)(r1 type1, r2 type2), 具体会有以下几种形式
1func f1() int {
2 return 1
3}
4
5func f2(a int, b float32) (int, string) {
6 return 2, "" // 返回多个值用逗号分开
7}
8
9func f3(a, b int) (x, y string) {...} // 参数列表类型相同可以写在一块
10func f4(a int, values ...int) {...} // 变参 values 是一个 slice []int<br/><br/>
11
12func f6() (i int) { //命名返回值是有初始零值的
13 return // 这里相当于 return i
14}1func foo(i *int) { // 参数为指针
2 *i = 10 // 指针位置赋值
3}
4
5func main() {
6 x := 3
7 foo(&x) // 传入地址
8 fmt.Println(x) // 输出的 x 为 10
9}Go 的内置函数 make(T) 和 new(T)
- make(T): 只用于 slice, map 以及 channel, 返回为 T 的值类型
- new(T): 用于值类型的内存分配,并设置为零值,它返回的是一个指向 T 类型的指针
其他的一些内置函数,len(), cap(), append(), copy(), delete(), close(), complex(), real(), image(), panic(), recover(), print(), println()
Go 的匿名函数也称为闭包,闭包对变量的捕获相当于引用传递,即不不会产生副本。可以修改外层的变量
1func main() {
2 i := 1
3 func() {
4 i++
5 }()
6 println(i) //2
7} 1func foo(who ...string) { // who 是一个 []string
2 for v := range who {
3 fmt.Println(v)
4 }
5}
6
7func main() {
8 foo("aa", "bb")
9 foo([]string{"cc", "dd"}...)
10 // foo([2]string{"cc", "dd"}...) 不能传入 array
11 arr := [2]string{"cc", "dd"}
12 foo(arr[0:]...) // 不能写成一行 foo(([2]string{"cc", "dd"})[0:])
13}1a := [2]int{1, 2}[1] // 合法
2b := []int{1, 2}[1] // 合法
3c := [2]int{1, 2}[0:1] // 不合法,invalid operation [2]int{...}[0:1] (slice of unaddressable value)[版权声明]
本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。