go int 转切片_DW-Go语言编程-Task06-数组、切片
數組、切片
數組
如何定義數組
數組是具有相同類型且長度固定的一組連續數據。數組元素可以通過索引(位置)來讀取(或者修改),索引從0開始,第一個元素索引為 0,第二個索引為 1,以此類推。在go語言中我們可以使用如下幾種方式來定義數組。
//方式一 var arr1 = [5]int{} //方式二 var arr2 = [5]int{1,2,3,4,5} //方式三 var arr3 = [5]int{3:10} //方式四var arr3 = []float32{1000.0, 2.0, 3.4, 7.0, 50.0}輸出以上三個變量的值如下所示:
arr1 [0 0 0 0 0] arr2 [1 2 3 4 5] arr3 [0 0 0 10 0] arr3 [1000 2 3.4 7 50]- 方法一在聲明時沒有為其指定初值,所以數組內的值被初始化為類型的零值。
- 方法二使用顯示的方式為數組定義初值。
- 方法三通過下標的方式為下標為3的位置賦上了初值10
- 方法四在申明時,并未指定數組大小,通過數組元素來確定數組大小
- 初始化數組中 {} 中的元素個數不能大于 [] 中的數字
而且在數組的定義是包含其長度的,也就是說[3]int與[4]int是兩種不同的數據類型。
如何操作數據
在上面的arr1我們沒有為其指定初值,那么之后我們可以通過循環的方式為其賦予初值
for i := 0; i < len(arr1); i++ {arr1[i] = i * 10}此時我們再輸出一下數組arr1,可以看到其值已經變化
arr1 update: [0 10 20 30 40]我們還可以通過循環的方式遍歷數組,與上面不同的是,for循環提供這樣的方式來為便利數組
for index, value := range arr1 {fmt.Printf("index: %d, value: %dn", index, value)}通過range來遍歷數組會有兩個返回值,其中第一個為數組的索引,第二個位置為對應的值,輸出結果如下:
index: 0, value: 0 index: 1, value: 10 index: 2, value: 20 index: 3, value: 30 index: 4, value: 40當然不想要索引值也是可以的,可以用_代替。
多維數組
二維數組是最簡單的多維數組,二維數組本質上是由一維數組組成的。二維數組定義方式如下:
var arrayName [ x ][ y ] variable_typevariable_type 為 Go 語言的數據類型,arrayName 為數組名,二維數組可認為是一個表格,x 為行,y 為列,下圖演示了一個二維數組 a 為三行四列:
二維數組中的元素可通過** a i **來訪問。
與其他語言一樣,go語言也可以定義多維數組,可以選擇的定義方式如下:
// 方式一 func main() {var arr4 = [5][5]int{{1, 2, 3, 4, 5},{6, 7, 8, 9, 10},}fmt.Println(arr4) }// 方式二 func main() {a := [3][4]int{{0, 1, 2, 3} , /* 第一行索引為 0 */{4, 5, 6, 7} , /* 第二行索引為 1 */{8, 9, 10, 11} , /* 第三行索引為 2 */}fmt.Println(a) }輸出當前數組,可以看到數組內的值如下所示
// 方式一 [[1 2 3 4 5] [6 7 8 9 10] [0 0 0 0 0] [0 0 0 0 0] [0 0 0 0 0]] // 方式二 [[0 1 2 3] [4 5 6 7] [8 9 10 11]]數組作為函數參數
go語言在傳遞數組時會對其進行拷貝,所以如果傳遞的是大數組的話會非常占內存,所以一般情況下很少直接傳遞一個數組,避免這種情況我們可以使用以下兩種方式:
- 傳遞數組的指針
- 傳遞切片(具體內容見下一小節)
向函數傳遞數組參數,你需要在函數定義時,聲明形參為數組,我們可以通過以下兩種方式來聲明:
方式一
形參設定數組大小:
void myFunction(param [10]int){}方式二
形參未設定數組大小:
void myFunction(param []int){}實例
讓我們看下以下實例,實例中函數接收整型數組參數,另一個參數指定了數組元素的個數,并返回平均值:
func getAverage(arr []int,size int) float32{var i intvar avg, sum float32 ?for i = 0; i < size; ++i {sum += arr[i]} ?avg = sum / size ?return avg; }接下來我們來調用這個函數:
package main ? import "fmt" ? func main() {/* 數組長度為 5 */var balance = []int {1000, 2, 3, 17, 50}var avg float32 ?/* 數組作為參數傳遞給函數 */avg = getAverage( balance, 5 ) ; ?/* 輸出返回的平均值 */fmt.Printf( "平均值為: %f ", avg ); } func getAverage(arr []int, size int) float32 {var i,sum intvar avg float32 ?for i = 0; i < size;i++ {sum += arr[i]} ?avg = float32(sum / size) ?return avg; }以上實例執行輸出結果為:
平均值為: 214.000000以上實例中我們使用的形參并為設定數組大小。
指針數組與數組指針
對于指針數組和數組指針在c或c++中也經常被討論,尤其對于初學者來說會分辨不清楚。其實在每個詞中間添加一個“的“就很好理解了,指針的數組,數組的指針。
1.指針數組
對于指針數組來說,就是:一個數組里面裝的都是指針,在go語言中數組默認是值傳遞的,所以如果我們在函數中修改傳遞過來的數組對原來的數組是沒有影響的。
func main() {var a [5]intfmt.Println(a)test(a)fmt.Println(a) } ? ? func test(a [5]int) {a[1] = 2fmt.Println(a) }輸出
[0 0 0 0 0] [0 2 0 0 0] [0 0 0 0 0]但是如果我們一個函數傳遞的是指針數組,情況會有什么不一樣呢?
func main() {var a [5]*intfmt.Println(a)for i := 0; i < 5; i++ {temp := ia[i] = &temp}for i := 0; i < 5; i++ {fmt.Print(" ", *a[i])}fmt.Println()test1(a)for i := 0; i < 5; i++ {fmt.Print(" ", *a[i])} } ? ? func test1(a [5]*int) {*a[1] = 2for i := 0; i < 5; i++ {fmt.Print(" ", *a[i])}fmt.Println() }我們先來看一下程序的運行結果
[<nil> <nil> <nil> <nil> <nil>]0 1 2 3 40 2 2 3 40 2 2 3 4可以看到初始化值全是nil,也就驗證了指針數組內部全都是一個一個指針,之后我們將其初始化,內部的每個指針指向一塊內存空間。
注:在初始化的時候如果直接另a[i] = &i那么指針數組內部存儲的全是同一個地址,所以輸出結果也一定是相同的
然后我們將這個指針數組傳遞給test1函數,對于數組的參數傳遞仍然是復制的形式也就是值傳遞,但是因為數組中每個元素是一個指針,所以test1函數復制的新數組中的值仍然是這些指針指向的具體地址值,這時改變a[1]這塊存儲空間地址指向的值,那么原實參指向的值也會變為2,具體流程如下圖所示。
2.數組指針
了解了指針數組之后,再來看一下數組指針,數組指針的全稱應該叫做,指向數組的指針,在go語言中我們可以如下操作。
func main() {var a [5]intvar aPtr *[5]intaPtr = &a//這樣簡短定義也可以aPtr := &afmt.Println(aPtr)test(aPtr)fmt.Println(aPtr) } ? ? func test(aPtr *[5]int) {aPtr[1] = 5fmt.Println(aPtr) }我們先定義了一個數組a,然后定一個指向數組a的指針aPtr,然后將這個指針傳入一個函數,在函數中我們改變了具體的值,程序的輸出結果
&[0 0 0 0 0] &[0 5 0 0 0] &[0 5 0 0 0]通過上面的圖我們可以看見雖然main和test函數中的aPtr是不同的指針,但是他們都指向同一塊數組的內存空間,所以無論在main函數還是在test函數中對數組的操作都會直接改變數組。
切片
因為數組是固定長度的,所以在一些場合下就顯得不夠靈活,所以go語言提供了一種更為便捷的數據類型叫做切片。切片操作與數組類似,但是它的長度是不固定的,可以追加元素,如果以達到當前切片容量的上限會再自動擴容。
如何定義切片
可以通過以下幾種方式定義切片
//方法一 var s1 = []int{} //方法二 var s2 = []int{1, 2, 3} //方法三 var s3 = make([]int, 5) //方法四 var s4 = make([]int, 5, 10)方法一聲明了一個空切片,方法二聲明了一個長度為3的切片,方法三聲明了一個長度為5的空切片,方法四聲明了一個長度為5容量為10的切片。可以看到切片的定義與數組類似,但是定義切片不需要為其指定長度。
我們可以通過len()和cap()這兩個函數來獲取切片的長度和容量,下面就來依次看下上面各切片的長度以及容量。
s1 [] 0 0 s2 [1 2 3] 3 3 s3 [0 0 0 0 0] 5 5 s4 [0 0 0 0 0] 5 10如果我們通過這種方式定義一個切片,那么他會被賦予切片的空值nil。
var s5 []int切片操作
我們可以通過如下的方式在數組和切片上繼續獲取切片
func main() {arr := [5]int{1, 2, 3, 4, 5}s := []int{6, 7, 8, 9, 10} ?s1 := arr[2:4]s2 := arr[:3]s3 := arr[2:]s4 := s[1:3] ?fmt.Println("s1:", s1)fmt.Println("s2:", s2)fmt.Println("s3:", s3)fmt.Println("s4:", s4) }程序的輸出結果如下
s1: [3 4] s2: [1 2 3] s3: [3 4 5] s4: [7 8]可以看到切片操作是“包左不包右”,例如arr[2:4]是選擇arr數組內下標為2,3的兩個元素。如果:左邊沒有起始位置則默認從頭開始,同理如果右邊沒有終止位置則默認到末尾。
切片的擴充與拼接
我們之前介紹了切片的定義以及一些切片的操作,下面就來看一下如何對切片進行擴充。
func main() {a := []int{1, 2, 3}b := a[1:3] ?b = append(b, 4)b = append(b, 5)b = append(b, 6)b = append(b, 7)fmt.Println(a)fmt.Println(b) }程序輸出結果如下
[1 2 3] [2 3 4 5 6 7]如果想要將兩個切片進行拼接可以使用如下這種方式:
func main() {a := []int{1, 2, 3}b := a[1:3] ?fmt.Println(b) ?a = append(a, b...)fmt.Println(a) } ? >>[2 3] >>[1 2 3 2 3]如果我們想要將一個切片的值復制給另一個切片,go語言也提供了非常簡便的方式。
func main() {a := []int{1, 2, 3}b := make([]int, 3)copy(b, a)fmt.Println(a)fmt.Println(b) } >>[1 2 3] >>[1 2 3]你不妨動手試一試下面幾個操作結果會怎么樣:
- 聲明b切片時,其長度比a切片長,復制結果是怎么樣的?
- 聲明b切片時,其長度比a切片短,復制結果是怎么樣的?
- 聲明b切片時,其長度被定義為0,那么調用copy函數會報錯嗎?
- No
切片與數組的關系
對于任何一個切片來說,其都有一個底層數組與之對應,我們可以將切片看作是一個窗口,透過這個窗口可以看到底層數組的一部分元素。
既然切片是引用底層數組的,需要注意的就是小切片引用大數組的問題,如果底層的大數組一直有切片進行引用,那么垃圾回收機制就不會將其收回,造成內存的浪費,最有效的做法是copy需要的數據后再進行操作。
總結
以上是生活随笔為你收集整理的go int 转切片_DW-Go语言编程-Task06-数组、切片的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: kmeans中的k的含义_硬质合金中P、
- 下一篇: MySQL进阶(DDL与DML)