本博客內容涉及到:切片
切片
1. 切片的概念
首先先對數組進行一下回顧:
- 數組定義完,長度是固定的,例如:
var num [5]int = [5]int{1,2,3,4,5}
定義的num數組長度是5,表示只能存儲5個整形數字,現在向數組num追加一個數字,代碼會出錯。
2. 使用數組作為函數參數進行傳遞時,如果實參為5個元素的整形數組,那么形參也必須為5個元素的整形數組,否則出錯。
而切片是一個可變長的序列(可以追加元素),可以包含任意類型的元素。切片比數組更靈活,更強大。
2. 切片和數組的區別
package mainimport "fmt"/*
演示切片和數組有什么區別
*/func main() {// 數組的基本定義a := [5]int{}fmt.Println(a)// 切片的基本定義s := []int{}fmt.Println(s)
}
輸出結果:
在數組定義過程中,必須指定數組的長度,并且在未給數組賦值時,數組元素默認為0。在給切片定義過程中[]
內無需賦值,且未進行賦值的切片為空。
下面使用append()
函數給切片追加數據。
【注意】:
使用append()
函數,當容量小于1024時是按照2倍容量擴容,當大于1024時不是按照兩倍容量進行擴容(每次約增加當前容量的1/4)。
s = append(s, 1, 2, 3, 4, 5, 6)fmt.Println(s)
輸出結果:
append()
函數中,第一個參數表示向哪個切片追加數據,后面表示具體追加的數據。
3.切片的定義方式
下面演示了切片的三種定義方式:
package mainimport "fmt"/*
演示切片的定義方式
*/func main() {// 第一種s1 := []int{}fmt.Println(s1)// 第二種var s2 []int //只是缺少了長度fmt.Println(s2)// 第三種s3 := make([]int, 5, 10) // 其中5是長度,10 是容量fmt.Println(s3)
}
輸出結果:
使用make()
函數時,前面一個數字為函數切片的長度,后面的那個數字是切片的容量。
**長度:**已經初始化的空間,切片初始空間默認值都是0。
**容量:**已經開辟的空間,包括已經初始化的空間和空閑的空間。
【注意】:
使用make()
函數時,切片的長度一定要小于容量。
切片賦值方式與數組相同。
4.切片截取
下面程序演示了切片的截取操作:
package mainimport "fmt"/*
演示切片的截取
*/
func main() {s := []int{1, 2, 3, 4, 5, 7, 8, 9, 10}// 從切片中截取數據slice := s[1:3:5]fmt.Println(slice)
}
輸出結果:
解釋s[1:3:5]
:
可以使用s[low: high: max]來表示:
- low:表示下標的起點,從該位置開始截取。
- high:表示取到哪結束,也就是下標的終點(不包含該位置)。左閉右開區間。
- max:用來計算容量,使用
max-low
可以計算出容量為多少。
5.修改截取切片的值
修改截取過后的新切片的值會影響到原來切片的值。
package mainimport "fmt"/*
演示修改截取的新切片的值,會影響到原切片的值
*/func main() {s := []int{1, 2, 3, 4, 5, 6, 7, 8, 10}fmt.Println(s)s1 := s[2:5]fmt.Println(s1)s1[0] = 100fmt.Println(s1)fmt.Println(s)
}
輸出如下:
切片進行截取操作后,截取后的切片指向的是原有的切片,所以在修改新切片的值會影響到原切片。
6. copy函數的使用
針對切片的操作常用的方法除了append()
方法外,還有copy方法。
基本語法:copy(切片1, 切片2)
將第二個切片中的元素,拷貝到第一個切片中。
package mainimport "fmt"/*
演示切片的拷貝
*/
func main() {s1 := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}s2 := []int{1, 1, 1, 1, 1, 1}copy(s1, s2)fmt.Println(s1)
}
輸出結果:
copy()
函數會使第二個切片中的值將第一個元素中的值覆蓋。
7.切片作為函數參數
同其它數據類型一樣,切片也可作為函數參數:
package mainimport "fmt"/*
演示切片作為函數參數
*/func InitData(num []int) {for i := 0; i < len(num); i++ {num[i] = i}
}func main() {// 創建一個切片s := make([]int, 10)// 使用函數初始化切片InitData(s)// 打印切片中的內容fmt.Println(s)
}
輸出結果如下:
通過這個程序可以發現,定義了一個切片s
,然后調用InitData()
函數,將切片s作為實參傳遞到該函數中,并在函數中對形參num
賦值,影響到了main()
函數中的切片s
.
接下來對比數組作為參數時,是否會影響到main()
函數中的值:
package mainimport "fmt"/*
演示數組作為函數參數時,是否會影響到main()函數中的值
*/func InitData(num [10]int) {for i := 0; i < len(num); i++ {num[i] = i}
}func main() {// 創建一個數組var s [10]int// 使用函數初始化切片InitData(s)// 打印數組中的內容fmt.Println(s)
}
輸出結果如下:
可以看到, 同樣的操作,但是InitData()
函數并未將main()
函數中的數組值改變。
值傳遞和引用
- 值傳遞:方法調用時,實參數把它的值傳遞給對應的形式參數,方法執行中形式參數值的改變不影響實際參數的值。
- 引用傳遞:也稱為傳地址。函數調用時,實際參數的引用(地址,而不是參數的值)被傳遞給函數中相對應的形式參數(實參與形參指向了同一塊存儲區域)。在函數執行中,對形式參數的操作實際上就是對實際參數的操作,方法執行中形式參數數值的改變將會影響時間參數的值。