fengchun_yuan 2 years ago
parent
commit
021743d6c3
2 changed files with 134 additions and 1 deletions
  1. BIN
      Go语言101/system.assets/image-20220906111657224.png
  2. 134 1
      Go语言101/system.md

BIN
Go语言101/system.assets/image-20220906111657224.png


+ 134 - 1
Go语言101/system.md

@@ -199,9 +199,142 @@ Go指针值是支持(使用比较运算符==和!=)比较的。 但是,两
 
 我并不是想说引用类型这个术语在Go中是完全没有价值的, 我只是想表达这个术语 是完全没有必要的,并且它常常在Go的使用中导致一些困惑。我推荐使用**指针持有者类型**来代替这个术语。 另外,我个人的观点是最好将引用这个词限定到只表示值 之间的关系,把它当作一个动词或者名词来使用,永远不要把它当作一个形容词来 使用。 这样将在使用Go的过程中避免很多困惑。
 
-# 数组、切片和映射
+# 数组、切片和映射(没全看懂)
 
+切片的长度和容量并不是一个概念
 
+切片长度不定、数组长度固定
 
+len(map类型) = 0
 
+映射和切片的复制,共享底层元素,它们的长 度和容量也相等。
+区别在于切片的复制,其中一个切片如果改变了长度或者容量,此变化不会体现到另一个切片中
+当一个数组被赋值给另一个数组,所有的元素都将被从源数组复制到目标数组。赋 值完成之后,这两个数组不共享任何元素
+
+## 添加和删除容器元素
+
+append内置函数,需要理解。
+
+## make函数
+
+可以用make创建切片和映射,数组不行
+
+```go
+1| make(S, length, capacity)
+2| make(S, length) // <=> make(S, length, length)
+```
+
+
+
+## new函数创造容器值
+
+到内置new函数可以用来为一个任 何类型的值开辟内存并返回一个存储有此值的地址的指针。 
+用new函数开辟出来的值均为零值。因为这个原因,new函数对于创建映射和切片值来说没有任何价值。
+
+```go
+6| m := *new(map[string]int) // <=> var m map[string]int
+7| fmt.Println(m == nil) // true
+8| s := *new([]int) // <=> var s []int
+9| fmt.Println(s == nil) // true
+10| a := *new([5]bool) // <=> var a [5]bool
+11| fmt.Println(a == [5]bool{}) // true
+```
+
+映射的整体修改是可以的,但是部分修改不被允许,但可读
+
+```go
+1| package main
+2|
+3| import "fmt"
+4|
+5| func main() {
+6| type T struct{age int}
+7| mt := map[string]T{}
+8| mt["John"] = T{age: 29} // 整体修改是允许的
+9| ma := map[int][5]int{}
+10| ma[1] = [5]int{1: 789} // 整体修改是允许的
+11|
+12| // 这两个赋值编译不通过,因为部分修改一个映射
+13| // 元素是非法的。这看上去确实有些反直觉。
+14| /*
+15| ma[1][1] = 123 // error
+16| mt["John"].age = 30 // error
+17| */
+18|
+19| // 读取映射元素的元素或者字段是没问题的。
+20| fmt.Println(ma[1][1]) // 789
+21| fmt.Println(mt["John"].age) // 29
+22| }
+```
+
+## 从数组或切片取子切片
+
+一个比较难理解的栗子
+
+```go
+1| package main
+2|
+3| import "fmt"
+4|
+5| func main() {
+6| a := [...]int{0, 1, 2, 3, 4, 5, 6}
+7| s0 := a[:] // <=> s0 := a[0:7:7]
+8| s1 := s0[:] // <=> s1 := s0
+9| s2 := s1[1:3] // <=> s2 := a[1:3]
+10| s3 := s1[3:] // <=> s3 := s1[3:7]
+11| s4 := s0[3:5] // <=> s4 := s0[3:5:7]
+12| s5 := s4[:2:2] // <=> s5 := s0[3:5:5]
+13| s6 := append(s4, 77)
+14| s7 := append(s5, 88)
+15| s8 := append(s7, 66)
+16| s3[1] = 99
+17| fmt.Println(len(s2), cap(s2), s2) // 2 6 [1 2]
+18| fmt.Println(len(s3), cap(s3), s3) // 4 4 [3 99 77 6]
+19| fmt.Println(len(s4), cap(s4), s4) // 2 4 [3 99]
+20| fmt.Println(len(s5), cap(s5), s5) // 2 2 [3 99]
+21| fmt.Println(len(s6), cap(s6), s6) // 3 4 [3 99 77]
+22| fmt.Println(len(s7), cap(s7), s7) // 3 4 [3 4 88]
+23| fmt.Println(len(s8), cap(s8), s8) // 4 4 [3 4 88 66]
+24| }
+
+```
+
+![image-20220906111657224](system.assets/image-20220906111657224.png)
+
+```go
+1| func f() []int {
+2| s := make([]int, 10, 100)
+3| return s[50:60]
+4| }
+```
+
+在上面这个函数中,子切片表达式的起始下标(50)比 s 的长度(10)要大,这是允许的。
+
+## 遍历
+
+遍历一个 nil 映射或者 nil 切片是允许的。这样的遍历可以看作是一个空操作。
+
+一些关于遍历映射条目的细节:
+
+- 映射中的条目的遍历顺序是不确定的
+- 遍历映射的过程中,如果一个还没被遍历到的条目被删除了,则此条目保证不会被遍历出来
+- 遍历过程中,一个新的条目被加入此映射,则此条目并不保证在此遍历过程中被遍历出来
+
+如果确保没有其它协程操纵一个映射 m , 则下面代码保证清空 m 中所有条目
+
+```go
+1| for key := range m {
+2| delete(m, key)
+3| }
+```
+
+也可以用传统的for循环来遍历
+
+```go
+1| for i := 0; i < len(anArrayOrSlice); i++ {
+2| element := anArrayOrSlice[i]
+3| // ...
+4| }
+
+```