-
指针
(1) 类型 *T 是指向 T 类型值的指针,其零值为 nil
var p *int
(2) & 操作符会生成一个指向其操作数的指针
i := 42 p = &i
(3) * 操作符表示指针指向的底层值
fmt.Println(*p) // 通过指针 p 读取 i *p = 21 // 通过指针 p 设置 i package main import "fmt" func main() { i, j := 42, 2701 p := &i // 指向 i fmt.Println(*p) // 通过指针读取 i 的值 *p = 21 // 通过指针设置 i 的值 fmt.Println(i) // 查看 i 的值 p = &j // 指向 j *p = *p / 37 // 通过指针对 j 进行除法运算 fmt.Println(j) // 查看 j 的值 }
-
结构体struct
(1) 一个结构体(struct)就是一组字段(field)
(2) 结构体字段使用点号.来访问
package main import "fmt" type Vertex struct { X int Y int } func main() { v := Vertex{1, 2} v.X = 4 fmt.Println(v.X) }
(3) 结构体字段也可以通过结构体指针来访问,即(*p).X,但是实际用p.X访问也支持
package main import "fmt" type Vertex struct { X int Y int } func main() { v := Vertex{1, 2} p := &v p.X = 1e9 fmt.Println(v) }
(4) 结构体__文法__
通过直接列出字段的值来新分配一个结构体,使用 Name: 语法可以仅列出部分字段,未列出字段被隐式赋予
package main import "fmt" type Vertex struct { X, Y int } var ( v1 = Vertex{1, 2} // 创建一个 Vertex 类型的结构体 v2 = Vertex{X: 1} // Y:0 被隐式地赋予 v3 = Vertex{} // X:0 Y:0 p = &Vertex{1, 2} // 创建一个 *Vertex 类型的结构体(指针) ) func main() { fmt.Println(v1, p, v2, v3) }
-
数组
(1) 类型 [n]T 表示拥有 n 个 T 类型的值的数组
(2) 数组的长度是其类型的一部分,因此__数组不能改变大小__
package main import "fmt" func main() { var a [2]string a[0] = "Hello" a[1] = "World" fmt.Println(a[0], a[1]) fmt.Println(a) primes := [6]int{2, 3, 5, 7, 11, 13} fmt.Println(primes) }
-
切片
(1) []T 表示一个元素类型为 T 的切片
(2) 切片则为数组元素提供动态大小的、灵活的视角
(3) 切片通过两个下标来界定,即一个上界和一个下界,二者以冒号分隔:a[low : high],包括low不包括high
package main import "fmt" func main() { primes := [6]int{2, 3, 5, 7, 11, 13} var s []int = primes[1:4] fmt.Println(s) }
(4) 切片本身不保存数据,只是__数组的引用__。所以同一数组上的所有切片或数组自身的元素修改,会被所有相关切片和数组本身观测到
package main import "fmt" func main() { names := [4]string{"John", "Paul", "George", "Ringo"} fmt.Println(names) a := names[0:2] b := names[1:3] fmt.Println(a, b) b[0] = "XXX" fmt.Println(a, b) fmt.Println(names) }
(5) 切片文法
[3]bool{true, true, false}会创建一个数组;
[]bool{true, true, false}会创建一个数组(但是没有名字),然后创建一个指向它全部数组元素范围的切片
(6) 切片的__默认下界是0__,默认上界是数组长度,可以省略下界和上界,此时采用的就是默认值
对于数组var a [10]int来说,以下切片是等价的: a[0:10] a[:10] a[0:] a[:]
(7) 切片的__长度len__和__容量cap__
1° 切片的__长度__就是它所包含的元素个数。
2° 切片的__容量__是从它的第一个元素开始数,到其底层数组元素末尾的个数
3° 切片 s 的长度和容量可通过表达式 len(s) 和 cap(s) 来获取
package main import "fmt" func main() { s := []int{2, 3, 5, 7, 11, 13} printSlice(s) // 截取切片使其长度为 0 s = s[:0] printSlice(s) // 拓展其长度 s = s[:4] printSlice(s) // 舍弃前两个值 s = s[2:] printSlice(s) } func printSlice(s []int) { fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s) }
(8) 切片的零值是__nil__
然而数组的零值不是nil,数组和struct一样,零值是内部元素的零值集合
(9) 切片可以用内建函数 make 来创建,make 函数会分配一个元素为零值的数组并返回一个引用了它的切片
package main import "fmt" func main() { a := make([]int, 5) printSlice("a", a) b := make([]int, 0, 5) printSlice("b", b) c := b[:2] printSlice("c", c) d := c[2:5] printSlice("d", d) } func printSlice(s string, x []int) { fmt.Printf("%s len=%d cap=%d %v\n", s, len(x), cap(x), x) }
(10) go语言中__数组很少使用,绝大多数情况都是用切片__
(11) 切片可以包括任何类型,可以创建切片的切片
package main import ( "fmt" "strings" ) func main() { // 创建一个井字板(经典游戏) board := [][]string{[]string{"_", "_", "_"}, []string{"_", "_", "_"}, []string{"_", "_", "_"}, } // 两个玩家轮流打上 X 和 O board[0][0] = "X" board[2][2] = "O" board[1][2] = "X" board[1][0] = "O" board[0][2] = "X" for i := 0; i < len(board); i++ { fmt.Printf("%s\n", strings.Join(board[i], " ")) } }
(12) 向切片追加元素–append
package main import "fmt" func main() { var s []int printSlice(s) // 添加一个空切片 s = append(s, 0) printSlice(s) // 这个切片会按需增长 s = append(s, 1) printSlice(s) // 可以一次性添加多个元素 s = append(s, 2, 3, 4) printSlice(s) } func printSlice(s []int) { fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s) }
(13) for 循环的 range 形式可遍历切片或映射
当使用 for 循环遍历切片时,每次迭代都会返回__两个值__。第一个值为当前元素的__下标__,第二个值为该下标所对应元素的__一份副本__
package main import "fmt" var pow = []int{1, 2, 4, 8, 16, 32, 64, 128} func main() { for i, v := range pow { fmt.Printf("2**%d = %d\n", i, v) } }
可以将下标或值赋予 _ 来__忽略__它。
for i, _ := range pow for _, value := range pow
若你只需要索引,忽略第二个变量即可。
for i := range pow
-
映射map
(1) 作用:将键映射到值
(2) 映射的零值为 nil
(3) make 函数会返回给定类型的映射,并将其__初始化__备用
package main import "fmt" type Vertex struct { Lat, Long float64 } var m map[string]Vertex func main() { m = make(map[string]Vertex) m["Bell Labs"] = Vertex{40.68433, -74.39967, } fmt.Println(m["Bell Labs"]) }
(4) 映射的文法(和struct用法差不多)
package main import "fmt" type Vertex struct { Lat, Long float64 } var m = map[string]Vertex{ "Bell Labs": Vertex{40.68433, -74.39967,}, "Google": Vertex{37.42202, -122.08408,}, } func main() { fmt.Println(m) }
若顶级类型只是一个类型名,你可以在文法的元素中省略它
(5) 在映射 m 中插入或修改元素
m[key] = elem
(6) 获取元素
elem = m[key]
(7) 删除元素
delete(m, key)
(8) 通过双赋值检测某个键__是否存在__
elem, ok := m[key]
若 key 在 m 中,ok 为 true ;否则,ok 为 false。
若 key 不在映射中,那么 elem 是该映射元素类型的零值
-
函数值
(1) 函数值可以用作函数的__参数__或__返回值__
package main import ( "fmt" "math" ) func compute(fn func(float64, float64) float64) float64 { return fn(3, 4) } func main() { hypot := func(x, y float64) float64 { return math.Sqrt(x*x + y*y) } fmt.Println(hypot(5, 12)) fmt.Println(compute(hypot)) fmt.Println(compute(math.Pow)) }
(2) 函数的__闭包__
Go 函数可以是一个闭包。闭包是一个函数值,它引用了其函数体之外的变量。该函数可以访问并赋予其引用的变量的值
package main import "fmt" func adder() func(int) int { sum := 0 return func(x int) int { sum += x return sum } } func main() { pos, neg := adder(), adder() for i := 0; i < 10; i++ { fmt.Println(pos(i), neg(-2*i),) } }
3_Structs_Slices_and_Maps
最新推荐文章于 2023-10-08 16:01:14 发布