1、數組
數組屬於值類型。
1)聲明
var 數組變量名 [元素數量]Type
- 數組變量名:數組聲明及使用時的變量名。
- 元素數量:數組的元素數量,可以是一個表達式,但最終通過編譯期計算的結果必須是整型數值,元素數量不能含有到運行時才能確認大小的數值。
- Type:可以是任意基本類型,包括數組本身,類型為數組本身時,可以實現多維數組。
默認情況下,數組的每個元素都會被初始化為元素類型對應的零值,對於數字類型來說就是 0,同時也可以使用數組字面值語法,用一組值來初始化數組。
在數組的定義中,如果在數組長度的位置出現“...”省略號,則表示數組的長度是根據初始化值的個數來計算。
示例:
package main import "fmt" func main() { var a [3]int for i := 0; i < len(a); i++{ fmt.Printf("%d, %d\n", i, a[i]) } var b = [3]int{1, 2} fmt.Println("----------------------------") for i := 0; i < len(b); i++{ fmt.Printf("%d, %d\n", i, b[i]) } c := [...]int{1, 2, 3} fmt.Println("----------------------------") for i := 0; i < len(c); i++{ fmt.Printf("%d, %d\n", i, c[i]) } }
2)比較兩個數組是否相等
如果兩個數組類型相同(包括數組的長度,數組中元素的類型)的情況下,我們可以直接通過較運算符(==
和!=
)來判斷兩個數組是否相等,只有當兩個數組的所有元素都是相等的時候數組才是相等的,不能比較兩個類型不同的數組,否則程序將無法完成編譯。
數組類型相同的數組之間可以互相賦值。
3)多維數組
示例:
package main import "fmt" func output(str string, arr [4][2]int) { fmt.Printf("ArrName: %s\n", str) for i := 0; i < 4; i++{ for j := 0; j < 2 ; j++ { fmt.Printf("%d, ", arr[i][j]) } fmt.Println() } } func main() { // 聲明一個二維整型數組,兩個維度的長度分別是 4 和 2 var a [4][2]int output("a", a) // 使用數組字面量來聲明並初始化一個二維整型數組 b := [4][2]int{{10, 11}, {20, 21}, {30, 31}, {40, 41}} output("b", b) // 聲明並初始化數組中索引為 1 和 3 的元素 c := [4][2]int{1: {20, 21}, 3: {40, 41}} output("c", c) // 聲明並初始化數組中指定的元素 d := [4][2]int{1: {0: 20}, 3: {1: 41}} output("d", d) }
2、切片
切片(slice)是對數組的一個連續片段的引用,所以切片是一個引用類型。Go語言中切片的內部結構包含地址、大小和容量,切片一般用於快速地操作一塊數據集合。
1)從數組或切片生成新的切片
從連續內存區域生成切片是常見的操作,格式如下:
slice [開始位置 : 結束位置]
- slice:表示目標切片對象;
- 開始位置:對應目標切片對象的索引;
- 結束位置:對應目標切片的結束索引。
從數組或切片生成新的切片擁有如下特性:
- 取出的元素數量為:結束位置 - 開始位置;
- 取出元素不包含結束位置對應的索引,切片最后一個元素使用 slice[len(slice)] 獲取;
- 當缺省開始位置時,表示從連續區域開頭到結束位置;
- 當缺省結束位置時,表示從開始位置到整個連續區域末尾;
- 兩者同時缺省時,與切片本身等效;
- 兩者同時為 0 時,等效於空切片,一般用於切片復位。
示例:
package main import "fmt" func main() { var a = [3]int{1,2,3} fmt.Println(a[1:2]) fmt.Println(a[:3]) fmt.Println(a[0:]) }
2)直接聲明切片
除了可以從原有的數組或者切片中生成切片外,也可以聲明一個新的切片,每一種類型都可以擁有其切片類型,表示多個相同類型元素的連續集合,因此切片類型也可以被聲明,切片類型聲明格式如下:
var name []Type
切片是動態結構,只能與 nil 判定相等,不能互相判定相等。
聲明新的切片后,可以使用 append() 函數向切片中添加元素。
示例:
package main import "fmt" func main() { var a []int // 聲明但未使用的切片的默認值是 nil var b = []int{} // 已經分配了內存 fmt.Println(a == nil) // true fmt.Println(b == nil) // false }
3)使用make()函數構造切片
如果需要動態地創建一個切片,可以使用 make() 內建函數,格式如下:
make( []Type, size, cap )
其中 Type 是指切片的元素類型,size 指的是為這個類型分配多少個元素,cap 為預分配的元素數量,這個值設定后不影響 size,只是能提前分配空間,降低多次分配空間造成的性能問題。
注意:使用 make() 函數生成的切片一定發生了內存分配操作,但給定開始與結束位置(包括切片復位)的切片只是將新的切片結構指向已經分配好的內存區域,設定開始與結束位置,不會發生內存分配操作。
示例:
package main import "fmt" func main() { a := make([]int, 2, 10) fmt.Println(a) fmt.Println("len=", len(a)) fmt.Println("cap=", cap(a)) }
4)添加元素
Go語言的內建函數 append() 可以為切片動態添加元素,在使用 append() 函數為切片動態添加元素時,如果空間不足以容納足夠多的元素,切片就會進行“擴容”,此時新切片的長度會發生改變。
尾部添加元素示例:
package main import "fmt" func main() { var a []int a = append(a, 1) // 追加1個元素 a = append(a, 1, 2) // 追加多個元素 a = append(a, []int{1, 2, 3}...) // 追加一個切片 fmt.Println(a) }
頭部添加元素示例:
package main import "fmt" func main() { var a = []int{1, 2, 3} a = append([]int{1}, a...) // 在開頭添加1個元素 a = append([]int{1, 2}, a...) // 在開頭添加1個切片 fmt.Println(a) }
切片中間插入元素示例:
package main import "fmt" func main() { var a = []int{1, 2, 3, 4, 5} // 在第2個位置插入一個切片 a = append(a[:2], append([]int{998, 999}, a[2:]...)...) /* 每個添加操作中的第二個 append 調用都會創建一個臨時切片,並將 a[i:] 的內容復制到新創建的切片中, 然后將臨時創建的切片再追加到 a[:i] 中。 */ fmt.Println(a) }
5)切片復制
Go語言的內置函數 copy() 可以將一個數組切片復制到另一個數組切片中,如果加入的兩個數組切片不一樣大,就會按照其中較小的那個數組切片的元素個數進行復制。
copy() 函數的使用格式:copy( destSlice, srcSlice []T) int
其中 srcSlice 為數據來源切片,destSlice 為復制的目標(也就是將 srcSlice 復制到 destSlice),來源和目標的類型必須一致,copy() 函數的返回值表示實際發生復制的元素個數。
示例:
package main import "fmt" func main() { slice1 := []int{1,2,3,4,5} slice2 := []int{100, 101, 102} count := copy(slice2, slice1) fmt.Println(count) count = copy(slice1, slice2) fmt.Println(count) }