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