A tour of Go (3) - 更多型別:struct, slice和對映
Saturday, December 19, 2020
A tour of Go (3) - 更多型別:struct, slice和對映
1. 指標
Go 擁有指標。指標儲存了值的記憶體地址。
型別 *T
是指向 T
型別值的指標。其零值為 nil
。
var p *int // 定義一個指向 int 型別的指標
&
操作符會生成一個指向其運算元的指標。
i := 42
p = &i // 將變數地址賦值給指標變數
*
操作符表示指標指向的底層值。
fmt.Println(*p) // 通過指標 p 讀取 i
*p = 21 // 通過指標 p 設定 i
與 C 不同,Go 沒有指標運算
2. 結構體
一個結構體(struct
)就是一組欄位(field)。
type Vertex struct {
X int
Y int
}
結構體欄位:結構體欄位使用點號來訪問。
v := Vertex{1, 2}
v.X = 4
結構體指標:結構體欄位可以通過結構體指標來訪問。
可以通過 (*p).X
來訪問其欄位 X
。允許我們使用隱式間接引用,直接寫 p.X
就可以。
p := &v // 不定義指標指向物件的屬性
p.X = 1e9
結構體文法:可以根據名字來賦值屬性,也可以只賦值部分,其他的根據型別自動賦值為預設值。
使用特殊字首 &
返回一個指向結構體的指標。
3. 陣列
型別 [n]T
表示擁有 n
個 T
型別的值的陣列。
表示式:
var a [10]int // 宣告一個擁有10個整數的陣列
陣列的長度是其型別的一部分,因此陣列不能改變大小。
4. 切片
型別 []T
表示一個元素型別為 T
的切片。
a[low : high] // 通過冒號來分隔上界和下界
a[1:4] // 半開區間,排除最後一個元素
切片下界的預設值為 0
,上界則是該切片的長度。
切片就像陣列的引用,切片本身並不儲存任何資料,更改切片的元素會修改其底層陣列中對應的元素。
切片文法類似於沒有長度的陣列文法。
[3]bool{true, true, false} // 陣列文法示例 []bool{true, true, false} // 建立一個和上面相同的陣列,然後構建一個引用了它的切片
切片擁有 長度 和 容量。
切片 s
的長度和容量可通過表示式 len(s)
和 cap(s)
來獲取。
指定下界會改變切片的容量,而上界則不會。
s := []int{2, 3, 5, 7, 11, 13} // len(s) = 6, cap = 6
s = s[:0] // len(s) = 0, cap = 6, 使用不同上界來引用,不會改變切片的容量!!
s = s[:4] // len(s) = 4, cap = 6, 增大上界,會拓展其長度,不改變容量!!
s = s[2:] // len(s) = 2, cap = 4, 指定下界,會捨棄前面n個值,改變切片的容量!!!
s = s[:5] // 報錯:slice bounds out of range [:5] with capacity 4
切片的零值是 nil
。nil
切片的長度和容量為 0 且沒有底層陣列。
表示式:var s[]int // 宣告一個 nil 切片
切片可以用內建函式 make
來建立,這也是你建立動態陣列的方式。
make
函式會分配一個元素為零值的陣列並返回一個引用了它的切片:
a := make([]int, 5) // len=5 cap=5 [0 0 0 0 0],省略了一個引數,預設len=cap=5
b := make([]int, 0, 5) // len=0 cap=5 []
切片的切片:切片可包含任何型別,甚至包括其它的切片。
board := [][]string{
[]string{"_", "_", "_"},
[]string{"_", "_", "_"},
[]string{"_", "_", "_"},
}
// 通過兩個索引值來改變指定的切片值
board[0][0] = "X"
為切片追加新的元素是種常用的操作,為此 Go 提供了內建的 append
函式。
var s []int // len=0 cap=0 []
s = append(s, 0) // len=1 cap=1 [0], append結果必須賦值給原來的切片
s = append(s, 1, 2, 3) // len=4 cap [0 1 2 3], 可以一次性新增多個元素
for
迴圈的 range
形式可遍歷切片或對映。
當使用 for
迴圈遍歷切片時,每次迭代都會返回兩個值。第一個值為當前元素的下標,第二個值為該下標所對應元素的一份副本。
for i, value := range pow
for i := range pow // 只要索引,可以直接忽略第第二個變數
for i, _ := range pow // 用 _ 來忽略value
for _, value := range pow // 用 _ 來忽略i
練習:切片 https://tour.go-zh.org/moretypes/18
題目描述:實現 Pic
。它應當返回一個長度為 dy
的切片,其中每個元素是一個長度為 dx
,元素型別為 uint8
的切片。當你執行此程式時,它會將每個整數解釋為灰度值(好吧,其實是藍度值)並顯示它所對應的影象。
影象的選擇由你來定。幾個有趣的函式包括 (x+y)/2
, x*y
, x^y
, x*log(y)
和 x%(y+1)
。
(提示:需要使用迴圈來分配 [][]uint8
中的每個 []uint8
;請使用 uint8(intValue)
在型別之間轉換;你可能會用到 math
包中的函式。)
package main
import (
"golang.org/x/tour/pic"
"math"
)
func Pic(dx, dy int) [][]uint8 {
img := make([][]uint8, dy) // 初始化切片,這裡用 :=
for i:=0; i<dy; i++ {
img[i] = make([]uint8, dx) // 這裡用 = ,不用 :=
for j:=0; j<dx; j++ {
img[i][j] = uint8(float64(i)*math.Log(float64(j))) //必須得型別轉換,再賦值
}
}
return img
}
func main() {
pic.Show(Pic)
}
i*j
結果:
(i+j)/2
結果:
i*log(j)
結果:
i%(j+1)
結果: