<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
在 Go 中,陣列和切片的功能其實是類似的,都是用來儲存一種型別元素的集合。陣列是固定長度的,而切片的長度是可以調整的
我們在宣告一個陣列的時候據必須要定義它的長度,並且不能修改。
陣列的長度是其型別的一部分:比如,[2]int 和 [4]int 是兩個不同的陣列型別。
// 1. 建立一維陣列 // 元素都是預設值 var arr1 [3]int // 指定長度並設定初始值 var arr2 = [3]int{1, 2, 3} var arr3 [3]int = [3]int{1, 2, 3} // 自動推導陣列長度 var arr4 = [...]int{1, 2, 3} // 指定特定下標的元素的值,其他的為預設值 var arr5 = [3]int{1: 9} // 2. 建立多維陣列 與一維陣列類似,不再贅述 var arr6 = [3][2]int{{1, 2}, {3, 4}, {5, 6}} fmt.Println(arr1) fmt.Println(arr2) fmt.Println(arr3) fmt.Println(arr4) fmt.Println(arr5) fmt.Println(arr6)
------結果----------------------------
[0 0 0]
[1 2 3]
[1 2 3]
[1 2 3]
[0 9 0]
[[1 2] [3 4] [5 6]]
var arr = [3]int{1, 2, 3} fmt.Println(arr) arr[2] = 9 fmt.Println(arr)
------結果----------------------------
[1 2 3]
[1 2 9]
方法一:for 迴圈遍歷
var arr = [3]int{1, 2, 3} for i := 0; i < len(arr); i++ { fmt.Println(arr[i]) }
------結果----------------------------
1
2
3
方法二:for range 迴圈遍歷
使用 index 和 value 分別接收每次迴圈到的位置的下標和值
var arr = [3]int{1, 2, 3} for index, value := range arr { fmt.Printf("index:%d value:%dn", index, value) }
------結果----------------------------
index:0 value:1
index:1 value:2
index:2 value:3
陣列比較的方法比較簡單,使用 == 符號即可
var arr = [3]int{1, 2, 3} var arr2 = [3]int{1, 2, 3} fmt.Println(arr == arr2) var arr3 = [...]int{1, 2, 3} fmt.Println(arr == arr3) var arr4 = [...]int{1, 2, 4} fmt.Println(arr == arr4)
------結果----------------------------
true
true
false
不能比較長度不同的陣列型別,否則編譯器會報錯,如下:
var arr = [3]int{1, 2, 3} var arr5 = [...]int{1, 2} fmt.Println(arr == arr5)
切片型別的定義
type slice struct { array unsafe.Pointer //指向陣列的指標 len int //切片的長度,可以理解為切片表示的元素的個數 cap int //容量,指標所指向的陣列長度(從指標位置向後) }
切片的特性
//直接宣告並賦值 s0 := []int{1, 2, 3, 4, 5} //通過陣列或者切片獲取 arr := [...]int{1, 2, 3, 4, 5} s1 := s0[:] // 切片 s0 中的全部元素 s2 := s0[:2] // 切片 s0 第一個元素到第二個元素 s3 := arr[3:] // 陣列 arr 從第四個元素開始向後的所有元素 s4 := arr[0:0] // 建立一個空切片 //通過 make(t Type, size ...IntegerType) 初始化, //接受的第一個 int 表示切片長度,第二個表示容量大小。如果只有一個int引數則預設長度和容量是相同的 s5 := make([]int, 5) //建立一個長度為 5 切片, s6 := make([]int, 5, 8) //建立一個長度為 5 容量為 8 的int型切片(長度為5的部分會被初始化為預設值) fmt.Println(s0, s1, s2, s3, s4, s5 ,s6)
-------結果-----------------------------------
[1 2 3 4 5] [1 2 3 4 5] [1 2] [4 5] [] [0 0 0 0 0] [0 0 0 0 0]
和陣列相同根據 index 賦值
//直接宣告並賦值 s0 := []int{1, 2, 3, 4, 5} fmt.Println(s0) s0[0] = 999 fmt.Println(s0)
-------結果-----------------------------------
[1 2 3 4 5]
[999 2 3 4 5]
我們可以通過 len(slice) 獲取一個切片的長度,可以通過 cap(slice) 獲取一個切片的容量。
容量:指標所指向的陣列長度(從指標位置向後),如何理解 從指標位置向後 這個意思,通過程式碼觀察:
s0 := []int{1, 2, 3, 4, 5} s1 := s0[1:3] //第二個元素到第三個元素 fmt.Printf("len: %dn", len(s1)) fmt.Printf("cap: %dn", cap(s1)) fmt.Println(s1 )
------結果---------------
len: 2
cap: 4
[2 3]
如上,s1 實際指向的陣列是 s0 的陣列的一個連續片段。
所有我們可以使用 cap 把切片 s1 指向的陣列(指標向後,包含指標)的去拿不元素都獲取到:
s0 := []int{1, 2, 3, 4, 5} s1 := s0[1:3] s2 := s1[:cap(s1)] fmt.Printf("len: %dn", len(s2)) fmt.Printf("cap: %dn", cap(s2)) fmt.Println(s2)
-------結果------------
len: 4
cap: 4
[2 3 4 5]
append 可以動態地向切片中追加元素
s0 := []int{1, 2, 3, 4, 5} s0 = append(s0, 6, 7, 8, 9, 10) //追加元素 fmt.Printf("len: %dn", len(s0)) fmt.Printf("cap: %dn", cap(s0)) fmt.Println(s0) s1 := []int{11, 12, 13, 14, 15} s0 = append(s0, s1...) //追加切片,切片需要解包 fmt.Printf("len: %dn", len(s0)) fmt.Printf("cap: %dn", cap(s0)) fmt.Println(s0)
len: 10
cap: 10
[1 2 3 4 5 6 7 8 9 10]
len: 15
cap: 20
[1 2 3 4 5 6 7 8 9 10 11 12 13 14 15]
我們可以發現,在第二次和第三次追加元素的時候,切片的容量發生了變化,兩次都是擴充為之前容量的兩倍。
但是一定都是兩倍擴容嗎?事實上不是的,如以下程式碼:
s0 := make([]int, 1000) fmt.Printf("len: %d, cap: %dn", len(s0), cap(s0)) s0 = append(s0, make([]int, 200)...) fmt.Printf("len: %d, cap: %dn", len(s0), cap(s0)) s0 = append(s0, make([]int, 400)...) fmt.Printf("len: %d, cap: %dn", len(s0), cap(s0))
-----結果--------------------------
len: 1000, cap: 1000
len: 1200, cap: 1536
len: 1600, cap: 2304
可以發現第一次擴容後,容量變為 1536,第二次擴容後容量又變成了 2304,並不是什麼兩倍的關係。
通過檢視 append 原始碼中的容量計算部分
func growslice(et *_type, old slice, cap int) slice { ... newcap := old.cap doublecap := newcap + newcap if cap > doublecap { newcap = cap } else { const threshold = 256 if old.cap < threshold { newcap = doublecap //小容量直接擴容到兩倍容量 } else { // Check 0 < newcap to detect overflow // and prevent an infinite loop. for 0 < newcap && newcap < cap { // Transition from growing 2x for small slices // to growing 1.25x for large slices. This formula // gives a smooth-ish transition between the two. //大容量取消了 1.25 倍擴容,選擇了一個更為平滑的擴容方案 newcap += (newcap + 3*threshold) / 4 } // Set newcap to the requested cap when // the newcap calculation overflowed. if newcap <= 0 { newcap = cap } } } var overflow bool var lenmem, newlenmem, capmem uintptr // Specialize for common values of et.size. // For 1 we don't need any division/multiplication. // For goarch.PtrSize, compiler will optimize division/multiplication into a shift by a constant. // For powers of 2, use a variable shift. switch { case et.size == 1: lenmem = uintptr(old.len) newlenmem = uintptr(cap) capmem = roundupsize(uintptr(newcap)) overflow = uintptr(newcap) > maxAlloc newcap = int(capmem) case et.size == goarch.PtrSize: lenmem = uintptr(old.len) * goarch.PtrSize newlenmem = uintptr(cap) * goarch.PtrSize capmem = roundupsize(uintptr(newcap) * goarch.PtrSize) overflow = uintptr(newcap) > maxAlloc/goarch.PtrSize newcap = int(capmem / goarch.PtrSize) case isPowerOfTwo(et.size): var shift uintptr if goarch.PtrSize == 8 { // Mask shift for better code generation. shift = uintptr(sys.Ctz64(uint64(et.size))) & 63 } else { shift = uintptr(sys.Ctz32(uint32(et.size))) & 31 } lenmem = uintptr(old.len) << shift newlenmem = uintptr(cap) << shift capmem = roundupsize(uintptr(newcap) << shift) overflow = uintptr(newcap) > (maxAlloc >> shift) newcap = int(capmem >> shift) default: lenmem = uintptr(old.len) * et.size newlenmem = uintptr(cap) * et.size capmem, overflow = math.MulUintptr(et.size, uintptr(newcap)) capmem = roundupsize(capmem) newcap = int(capmem / et.size) } ... return slice{p, old.len, newcap} }
從原始碼中可以得知:
到此這篇關於Golang陣列與切片輕鬆掌握的文章就介紹到這了,更多相關Golang陣列和切片內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45