日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

从一道题来看看golang中的slice作为参数时的现象

發布時間:2023/11/16 windows 61 coder
生活随笔 收集整理的這篇文章主要介紹了 从一道题来看看golang中的slice作为参数时的现象 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1、題目

最近看群友在群里問一道關于golang中slice的題,題目如下:

package main

import "fmt"

func main() {
	k := []int{1, 2, 3, 4}
	k = append(k, 5, 6)
	fmt.Printf("k --> value: %v, add: %p, cap: %d\n", k, k, cap(k))

	ap(k)
	fmt.Printf("k --> value: %v, add: %p, cap: %d\n", k, k, cap(k))

}

func ap(k []int) {
	k = append(k, 7, 8)
	fmt.Printf("k --> value: %v, add: %p, cap: %d\n", k, k, cap(k))
}

執行結果:

k --> value: [1 2 3 4 5 6], add: 0xc00001e180, cap: 8
k --> value: [1 2 3 4 5 6 7 8], add: 0xc00001e180, cap: 8
k --> value: [1 2 3 4 5 6], add: 0xc00001e180, cap: 8

乍一看,還挺奇怪的,變量k的地址都是一樣的,為啥會執行ap函數時,打印出來的東西不一樣呢?

其實對于初次接觸 golang 的 gopher 而言,這個問題確實有點奇怪,書上不是說slice是引用類型,golang 中的函數傳參是值拷貝,那么在函數傳遞 slice 時,傳遞也是地址,為啥對地址指向的內容做了修改后,并沒有影響到其他指向同一地址的變量呢?

想要理解這里面的原理,需要了解下面的基礎知識,接下來我們先看看前置知識,學習完這些前置的理論后,相信大家都已經有了自己的理解與答案。

PS: 要是有理解不對的地方,請不吝賜教哈,謝謝。

2、前置理論

2.1、切片的本質

下面的介紹基于 go 1.18,golang中關于 slice 封裝的源碼位于 runtime/slice.go 中。

切片的本質就是對底層數組的封裝,切片實際上是一個 struct ,包含了三個字段:底層數組的指針、切片的長度(len)和切片的容量(cap)。

type slice struct {
	array unsafe.Pointer  // 數組指針
	len   int  // 長度
	cap   int  // 容量
}

slice 作為參數傳遞的時候,是將slice struct中的各個字段逐一復制到新的變量中去的,其中 array 字段是底層數組的首地址

我們一起來看看題目中變量K的初始化

k := []int{1, 2, 3, 4}
k = append(k, 5, 6)

變量 K 示意圖:

執行 ap 函數后

func ap(k []int) {
	k = append(k, 7, 8)  // 無需擴容,容量足夠
	fmt.Printf("k --> value: %v, add: %p, cap: %d\n", k, k, cap(k))
}

函數內變量k的示意圖:

2.2、格式化字符串%p打印slice時顯示的是什么

這個問題呢,推薦大家看下這篇文章,比我說得清楚寫。

[golang slice切片到底是指針嗎?為什么%p輸出的切片是地址?](https://segmentfault.com/a/1190000042430248)

這里我們寫一個demo驗證下

func main() {
	k := []int{1, 2, 3, 4}
	fmt.Printf("k    --> add: %p\n", k)
	fmt.Printf("k[0] --> add: %p\n", &k[0])
}


執行結果:
k    --> add: 0xc000136000
k[0] --> add: 0xc000136000

3、再看題目

了解了上面的知識后,再看開頭的題目就很簡單了,變量k 傳給 ap 函數函數時,雖然函數 ap 的形參也叫 k,但是已經不是同一個變量了,只是兩個 slice 指向的底層數組是同一個而已,所以使用 %p 打印時,顯示的地址是一樣的。

package main

import "fmt"

func main() {
	k := []int{1, 2, 3, 4}
	k = append(k, 5, 6)
	fmt.Printf("k --> value: %v, add: %p, len: %d, cap: %d\n", k, k, len(k), cap(k))
	fmt.Printf("k --> add: %p\n", &k)

	ap(k)
	fmt.Printf("k --> value: %v, add: %p, len: %d, cap: %d\n", k, k, len(k), cap(k))
	fmt.Printf("k --> add: %p\n", &k)
}

func ap(k []int) {
	k = append(k, 7, 8)
	fmt.Printf("k --> value: %v, add: %p, len: %d, cap: %d\n", k, k, len(k), cap(k))
	fmt.Printf("k --> add: %p\n", &k)
}

執行結果:

k --> value: [1 2 3 4 5 6], add: 0xc00001e180, len: 6, cap: 8
k --> add: 0xc00000c030
k --> value: [1 2 3 4 5 6 7 8], add: 0xc00001e180, len: 8, cap: 8
k --> add: 0xc00000c078
k --> value: [1 2 3 4 5 6], add: 0xc00001e180, len: 6, cap: 8
k --> add: 0xc00000c030

想要 ap 函數執行后的結果,能夠改變外面的變量k也很簡單,將函數中的形參k返回出去就可以了。類似這樣:

func ap(k []int) []int {
	k = append(k, 7, 8)
	return k
}

k = ap(k)

是不是有點像 append 內置函數

總結

以上是生活随笔為你收集整理的从一道题来看看golang中的slice作为参数时的现象的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。