課程地址 go-class-slides/xmas-2020 at trunk · matt4biz/go-class-slides (github.com)
主講老師 Matt Holiday
05-Arrays, Slices, and Maps
In memory

string、array、slice 在記憶體中是連續存盤的,map不是連續存盤的,
Array

在創建陣列的時候需要指定大小,如果不指定需要使用 ... ,圖中 a、b 將是固定的 24 位元組物件(int在64位作業系統上默認為int64),一旦設定不能改變,
d=b 中,由于陣列只是一塊記憶體,并不是像字串那樣的描述符,我們只是物理地復制了位元組,當陣列大小不一致時,無法進行拷貝復制,
Slice

切片有描述符,指向一個特定的記憶體地址,它的作業方式類似于字串的作業方式,
切片描述符包含 data、len、capacity,
append 方法需要把回傳值重新賦給 a,假設 a 指向的記憶體區域已經滿了,再添加元素就要開辟新的更大的記憶體區域存放,
a=b 表示 b 描述符的內容被拷貝到 a 描述符中,
e:=a 新建一個描述符,內容與 a 描述符內的一致,
切片可以被切片(截取)操作,就像從字串(前面的os.Args[1:])中取出切片,從切片陣列切片等,
package main
import "fmt"
func main() {
t := []byte("string")
fmt.Println(len(t), t)
fmt.Println(t[2])
fmt.Println(t[:2])
fmt.Println(t[2:])
fmt.Println(t[3:5], len(t[3:5]))
}
6 [115 116 114 105 110 103]
114
[115 116]
[114 105 110 103]
[105 110] 2
fence post error

柵欄柱錯誤:假設我有三個柵欄部分,我必須有四個柵欄在他們旁邊將它們固定住,(不懂直接看圖)
Compare Array、Slice

切片可以是任意長度,而且大部分 Go 的標準庫使用切片作為引數,
切片是不能進行比較的,想進行比較可以使用陣列,這也導致切片不能作為 Map Key,
陣列可以作為一些演算法必備的陣列,大小固定,值不改變,近似于偽常量,注意,不能添加 const 常量關鍵字,只有數字,字串,布林值可以作為常量,

Example

a[0]=4 因為 a 只是 w 的值拷貝(陣列),所以修改后 w 并沒有被修改,
b[0]=3 將會使 x 修改,因為兩者 data 都指向同一個記憶體地址,(但是要注意,這是值拷貝,如果添加元素過多,會導致 b 的 data 指標使用新的記憶體地址而 x 還是指向原來的)
copy(c, b) 函式不會因為切片大小不同出錯,會盡可能把 b 切片中的元素拷貝到 c 中,
我們可以對陣列切片如 z := a[0:2] z 將是一個切片,指向 a 的前兩個元素,go 會自動提供陣列來保存,
Map

假設要計算一個檔案中不同單詞出現的次數,就可以使用 Maps,是一個 Hash table,
m 是一個描述符,但是整體為空, p 的 data 指標指向一個哈希表,

map 與 map 間不能進行比較,只能進行 nil 比較,
可以查看 map 的長度,不能查看 map 的容量,

可以通過獲取第二個引數判斷鍵值對是否存在,
Built in functions

Make nil useful

由于 len、cap、range 這些內建函式是安全的,我們不需要 if 判斷 nil 就可以直接使用,
range 將會跳過 nil、empty 的回圈物件,
Quote

一種不影響你思考編程的方式的語言是不值得了解的
Practice
撰寫一個段落單詞計數器,輸出前三個出現次數最多的單詞,
main.go
package main
import (
"bufio"
"fmt"
"os"
"sort"
)
func main() {
scan := bufio.NewScanner(os.Stdin)
words := make(map[string]int)
// ^ 默認是按行讀取,所以手動指定按單詞讀取
scan.Split(bufio.ScanWords)
for scan.Scan() {
words[scan.Text()]++
}
fmt.Println(len(words), "unique words")
type kv struct {
key string
val int
}
var ss []kv
for k, v := range words {
ss = append(ss, kv{k, v})
}
// ^ 直接修改原切片
sort.Slice(ss, func(i, j int) bool {
return ss[i].val > ss[j].val
})
for _, s := range ss[:3] {
fmt.Println(s.key, "appears", s.val, "times")
}
}
scan.Split(bufio.ScanWords) Scanner 默認是按行讀取,所以手動指定按單詞讀取,
kv{k, v} 結構體的初始化
sort.Slice 函式直接修改原切片,傳入的函式在 return 前面的元素排在切片的前面,如左>右,則大的元素在切片最前面,屬于降序排序,
test.txt
matt went to greece
where did matt go
alan went to rome
matt didn't go there
第一行是空行是有原因的,這是 BOM頭(Byte Order Mark) 導致的,具體請看另一篇文章
重定向管道流讀取TXT文本第一次讀取為""空字串 - 小能日記 - 博客園 (cnblogs.com)
result
cat test.txt | go run .
12 unique words
matt appears 3 times
to appears 2 times
go appears 2 times
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/454694.html
標籤:Go
