成人怡红院-成人怡红院视频在线观看-成人影视大全-成人影院203nnxyz-美女毛片在线看-美女免费黄

站長資訊網
最全最豐富的資訊網站

大型迷惑現場之[]*T是什么?*[]T是什么?*[]*T又是什么?

最近看到一段十分詭異的代碼,包含了“[]*T”“*[]T”和“*[]*T”,乍一看都是一樣的,但我們仔細觀察就發現他們的不同之處。今天我們就來介紹一下golong的“[]*T”“*[]T”和“*[]*T”,了解一下他們之間的不同,一起來看看

作為一個 Go 語言新手,看到一切”詭異“的代碼都會感到好奇;比如我最近看到的幾個方法;偽代碼如下:

func FindA() ([]*T,error) { }  func FindB() ([]T,error) { }  func SaveA(data *[]T) error { }  func SaveB(data *[]*T) error { }

相信大部分剛入門 Go 的新手看到這樣的代碼也是一臉懵逼,其中最讓人疑惑的就是:

[]*T *[]T *[]*T

這樣對切片的聲明,先不看后面兩種寫法;單獨看 []*T 還是很好理解的:
該切片中存放的是所有 T 的內存地址,會比存放 T 本身來說要更省空間,同時 []*T 在方法內部是可以修改 T 的值,而[]T 是修改不了。

func TestSaveSlice(t *testing.T) {     a := []T{{Name: "1"}, {Name: "2"}}     for _, t2 := range a {         fmt.Println(t2)     }     _ = SaveB(a)     for _, t2 := range a {         fmt.Println(t2)     }  } func SaveB(data []T) error {     t := data[0]     t.Name = "1233"     return nil }  type T struct {     Name string }

比如以上例子打印的是

{1} {2} {1} {2}

只有將方法修改為

func SaveB(data []*T) error {     t := data[0]     t.Name = "1233"     return nil }

才能修改 T 的值:

&{1} &{2} &{1233} &{2}

示例

下面重點來看看 []*T 與 *[]T 的區別,這里寫了兩個 append 函數:

func TestAppendA(t *testing.T) {     x:=[]int{1,2,3}     appendA(x)     fmt.Printf("main %vn", x) } func appendA(x []int) {     x[0]= 100     fmt.Printf("appendA %vn", x) }

先看第一種,輸出是結果是:

appendA [1000 2 3] main [1000 2 3]

說明在函數傳遞過程中,函數內部的修改能夠影響到外部。


下面我們再看一個例子:

func appendB(x []int) {     x = append(x, 4)     fmt.Printf("appendA %vn", x) }

最終結果卻是:

appendA [1 2 3 4] main [1 2 3]

沒有影響到外部。

而當我們再調整一下會發現又有所不同:

func TestAppendC(t *testing.T) {     x:=[]int{1,2,3}     appendC(&x)     fmt.Printf("main %vn", x) } func appendC(x *[]int) {     *x = append(*x, 4)     fmt.Printf("appendA %vn", x) }

最終的結果:

appendA &[1 2 3 4] main [1 2 3 4]

可以發現如果傳遞切片的指針時,使用 append 函數追加數據時會影響到外部。

slice 原理

在分析上面三種情況之前,我們先來了解下 slice 的數據結構。

直接查看源碼會發現 slice 其實就是一個結構體,只是不能直接對外訪問。

源碼地址 runtime/slice.go

其中有三個重要的屬性:

屬性 含義
array 底層存放數據的數組,是一個指針。
len 切片長度
cap 切片容量 cap>=len

提到切片就不得不想到數組,可以這么理解:

切片是對數組的抽象,而數組則是切片的底層實現。

其實通過切片這個名字也不難看出,它就是從數組中切了一部分;相對于數組的固定大小,切片可以根據實際使用情況進行擴容。

所以切片也可以通過對數組"切一刀"獲得:

x1:=[6]int{0,1,2,3,4,5} x2 := x[1:4] fmt.Println(len(x2), cap(x2))

其中 x1 的長度與容量都是6。

x2 的長度與容量則為3和5。

  • x2 的長度很容易理解。

  • 容量等于5可以理解為,當前這個切片最多可以使用的長度。

因為切片 x2 是對數組 x1 的引用,所以底層數組排除掉左邊一個沒有被引用的位置則是該切片最大的容量,也就是5。

同一個底層數組

以剛才的代碼為例:

func TestAppendA(t *testing.T) {     x:=[]int{1,2,3}     appendA(x)     fmt.Printf("main %vn", x) } func appendA(x []int) {     x[0]= 100     fmt.Printf("appendA %vn", x) }

在函數傳遞過程中,main 中的 x 與 appendA 函數中的 x 切片所引用的是同個數組。

所以在函數中對 x[0]=100,main函數中也能獲取到。

本質上修改的就是同一塊內存數據。

值傳遞帶來的誤會

在上述例子中,在 appendB 中調用 append 函數追加數據后會發現 main 函數中并沒有受到影響,這里我稍微調整了一下示例代碼:

func TestAppendB(t *testing.T) {     //x:=[]int{1,2,3}     x := make([]int, 3,5)     x[0] = 1     x[1] = 2     x[2] = 3     appendB(x)     fmt.Printf("main %v len=%v,cap=%vn", x,len(x),cap(x)) } func appendB(x []int) {     x = append(x, 444)     fmt.Printf("appendB %v len=%v,cap=%vn", x,len(x),cap(x)) }

主要是修改了切片初始化方式,使得容量大于了長度,具體原因后續會說明。

輸出結果如下:

appendB [1 2 3 444] len=4,cap=5 main [1 2 3] len=3,cap=5

main 函數中的數據看樣子確實沒有受到影響;但細心的朋友應該會注意到 appendB 函數中的 x 在 append() 之后長度 +1 變為了4。

而在 main 函數中長度又變回了3.

這個細節區別就是為什么 append() "看似" 沒有生效的原因;至于為什么要說“看似”,再次調整了代碼:

func TestAppendB(t *testing.T) {     //x:=[]int{1,2,3}     x := make([]int, 3,5)     x[0] = 1     x[1] = 2     x[2] = 3     appendB(x)     fmt.Printf("main %v len=%v,cap=%vn", x,len(x),cap(x))      y:=x[0:cap(x)]     fmt.Printf("y %v len=%v,cap=%vn", y,len(y),cap(y)) }

在剛才的基礎之上,以 append 之后的 x 為基礎再做了一個切片;該切片的范圍為 x 所引用數組的全部數據。

再來看看執行結果如何:

appendB [1 2 3 444] len=4,cap=5 main [1 2 3] len=3,cap=5 y [1 2 3 444 0] len=5,cap=5

會神奇的發現 y 將所有數據都打印出來,在 appendB 函數中追加的數據其實已經寫入了數組中,但為什么 x 本身沒有獲取到呢?

看圖就很容易理解了:

  • 在appendB中確實是對原始數組追加了數據,同時長度也增加了。

  • 但由于是值傳遞,所以 slice 這個結構體即便是修改了長度為4,也只是對復制的那個對象修改了長度,main 中的長度依然為3.

  • 由于底層數組是同一個,所以基于這個底層數組重新生成了一個完整長度的切片便能看到追加的數據了。

所以這里本質的原因是因為 slice 是一個結構體,傳遞的是值,不管方法里如何修改長度也不會影響到原有的數據(這里指的是長度和容量這兩個屬性)。

切片擴容

還有一個需要注意:

剛才特意提到這里的例子稍有改變,主要是將切片的容量設置超過了數組的長度;

如果不做這個特殊設置會怎么樣呢?

func TestAppendB(t *testing.T) {     x:=[]int{1,2,3}     //x := make([]int, 3,5)     x[0] = 1     x[1] = 2     x[2] = 3     appendB(x)     fmt.Printf("main %v len=%v,cap=%vn", x,len(x),cap(x))      y:=x[0:cap(x)]     fmt.Printf("y %v len=%v,cap=%vn", y,len(y),cap(y)) } func appendB(x []int) {     x = append(x, 444)     fmt.Printf("appendB %v len=%v,cap=%vn", x,len(x),cap(x)) }

輸出結果:

appendB [1 2 3 444] len=4,cap=6 main [1 2 3] len=3,cap=3 y [1 2 3] len=3,cap=3

這時會發現 main 函數中的 y 切片數據也沒有發生變化,這是為什么呢?

這是因為初始化 x 切片時長度和容量都為3,當在 appendB 函數中追加數據時,會發現沒有位置了。

這時便會進行擴容:

  • 將老數據復制一份到新的數組中。

  • 追加數據。

  • 將新的數據內存地址返回給 appendB 中的 x .

同樣的由于是值傳遞,所以 appendB 中的切片換了底層數組對 main 函數中的切片沒有任何影響,也就導致最終 main 函數的數據沒有任何變化了。

傳遞切片指針

有沒有什么辦法即便是在擴容時也能對外部產生影響呢?

func TestAppendC(t *testing.T) {     x:=[]int{1,2,3}     appendC(&x)     fmt.Printf("main %v len=%v,cap=%vn", x,len(x),cap(x)) } func appendC(x *[]int) {     *x = append(*x, 4)     fmt.Printf("appendC %vn", x) }

輸出結果為:

appendC &[1 2 3 4] main [1 2 3 4] len=4,cap=6

這時外部的切片就能受到影響了,其實原因也很簡單;

剛才也說了,因為 slice 本身是一個結構體,所以當我們傳遞指針時,就和平時自定義的 struct 在函數內部通過指針修改數據原理相同。

最終在 appendC 中的 x 的指針指向了擴容后的結構體,因為傳遞的是 main 函數中 x 的指針,所以同樣的 main 函數中的 x 也指向了該結構體。

總結

所以總結一下:

  • 切片是對數組的抽象,同時切片本身也是一個結構體。

  • 參數傳遞時函數內部與外部引用的是同一個數組,所以對切片的修改會影響到函數外部。

  • 如果發生擴容,情況會發生變化,同時擴容會導致數據拷貝;所以要盡量預估切片大小,避免數據拷貝。

  • 對切片或數組重新生成切片時,由于共享的是同一個底層數組,所以數據會互相影響,這點需要注意。

  • 切片也可以傳遞指針,但場景很少,還會帶來不必要的誤解;建議值傳值就好,長度和容量占用不了多少內存。

相信使用過切片會發現非常類似于 Java 中的 ArrayList,同樣是基于數組實現,也會擴容發生數據拷貝;這樣看來語言只是上層使用的選擇,一些通用的底層實現大家都差不多。

這時我們再看標題中的 []*T *[]T *[]*T 就會發現這幾個并沒有什么聯系,只是看起來很像容易唬人。

有需要的可以看golong教程哦

贊(0)
分享到: 更多 (0)
?
網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號
国产精品日日摸夜夜添夜夜添| 吃奶呻吟打开双腿做受在线视频| FREEⅩ性CHINESE中国| MM1313午夜视频在线观看| 播放片高清MV在线观看| 父母全家儿女大联欢第14集| 国产精品国产自线拍免费| 国产一区二区三精品久久久无广告| 花火と在线观看动漫免费| 久久久久久精品免费免费WEI| 男吃乳尖玩奶头高潮视频| 欧美一级 片内射黑人B| 三个女儿一锅烩大团圆全文阅读| 无码中文字幕AV免费放DVD| 亚洲欧洲老熟女AV| 50岁露脸老熟女88AV| 成人亚洲AV日韩AV欧v| 国产天堂亚洲国产碰碰| 看全色黄大色大片免费久久| 人妻丰满熟妇av无码区HD优| 无码毛片一区二区三区本码视频| 亚洲欧美另类在线视频| AA级女人大片喷水视频免费| 国产98在线 | 免费| 欧美精品亚洲精品日韩专区VA| 亚洲AV无码不卡一区二区三区| 精品一区二区三区免费视频| CHINESE叫床对白VIDEOS| 特级西西WWW444人体聚色| 久久久久久久精品国产免费…| 丰满熟妇岳AV无码区HD| 宝贝你下面喷潮了| 亚洲女久久久噜噜噜熟女| 国产精品无码素人福利不卡| 久久无码人妻一区二区三区 | 性XXXXBBBB农村小树林| 野花おっさんとわたし| 成人无码午夜在线观看| 无码色AV一二区在线播放| 中国无码人妻丰满熟妇啪啪软件| 成人国产精品秘片多多| 狠狠澡人人添人人爽人妻少妇| 年轻老师的滋味5| 无码国产色欲XXXX视频| 欧美性猛交内射兽交老熟妇| 人妻精品丝袜一区二区无码AV| 秋霞国产午夜伦午夜福利片 | 欧美性一区二区三区| 性少妇JEAⅠOUSVU片| 51精产国品一二三产区区| 国产精品无码AV不卡| 免费看老外操B视频| 无码人妻精品内射一二三AV| 中文乱码人妻系列一区二区| 国产精品成人网站| 内射人妻无码色AB麻豆| 亚洲AV日韩AV奶水无码| YY1111111少妇无码影院| 精品国产一区二区三区久久影院 | 日子我妈妈毛片儿电影| 亚洲国产精品成人久久| 差差漫画页面免费漫画欢迎你| 久艾草久久综合精品无码| 熟妇内射在线二区| 1—36集电视剧免费观看36集| 国产欧洲野花A级| 强行挺进美艳老师的后臀| 亚洲国产欧美在线人成最新| 被黑人伦流澡到高潮HNP动漫| 精品国产一区二区三区色欲| 日韩精品无码免费专区网站| 一边捏奶头一边高潮视频| 国产精品无码A∨精品影院| 欧洲美熟女乱又伦AV影片| 亚洲天堂无码高清高潮| 国产精品国产三级国产AV′| 欧洲多毛裸体XXXXX| 一本大道香蕉久中文在线播放| 国产精品理论片在线观看| 欧美日韩不卡合集视频| 公交车被CAO得合不拢腿视频| 国产成人无码A区在线观看视频 | 无码高潮爽到爆的喷水视频| 做AJ的视频大全电视剧| 黑人异族巨大巨大巨粗| 色偷拍 自怕 亚洲 10P| 重口老太大和小伙乱| 狠狠色综合网久久久久久| 熟妇人妻无乱码中文字幕蜜桃| av 成人 亚洲无码| 久久人人爽人人爽人人片AV超碰| 亚洲 小说区 图片区 都市| 成人亚洲欧美成ΑⅤ人在线观看| 男孩子都会夹住女孩子头发| 亚洲国产精品久久无码中文字蜜桃| 丰满少妇被猛烈进入无码| 欧美黑人巨大VIDEOS精品| 亚洲综合一区二区三区无码| 国产一区二区三区水蜜桃| 四虎永久在线精品无码视频| 暗交小拗女一区二| 女班长给我看她小积积作文| 亚洲一区二区三区成人片在线观看 | 白天躁晚上躁天天躁| 妺妺晚上扒我内裤吃我精子H| 亚洲一线产区二线产区| 娇妻初尝粗大滋味借种韩国电影| 无人区码一码二码三码是什么意思| 风流老熟女一区二区三区 | SUNTEK中老年妈妈| 免费中国帅气体育生GARY| 一区二区三区高清AV专区| 精品亚洲国产成人小电影| 亚洲成AV人影片在线观看| 国产无遮挡又黄又爽高潮| 无码人妻一区二区三区在线| 国产成人亚洲综合精品| 天堂А√在线地址资源| 父债子偿BY画崖海棠| 色8激情欧美成人久久综合电 | 日韩乱码人妻无码中文字幕久久| 波多野结衣AV一区二区全免费观看| 欧美美女多人群交视频| CHINESE偷拍宾馆TUBE| 女人扒开屁股桶爽30分钟| 中文字日产幕码三区做法| 蜜桃视频一区二区三区| 中文字幕精品第一区二区三区 | 97人妻成人免费视频| 女性自慰网站免费观看W| 99精产国品一二三产区区| 欧美白人乱大交XXXX潮喷| AA级女人大片喷水视频免费| 欧美巨大巨粗黑人性AAAAAA| JZZJZZ免费观看视频| 人与善交XUANWEN18| 大肉大捧一进一出视频| 少妇一晚三次一区二区三区| 国产AV成人一区二区三区高清| 婷婷五月综合激情| 国产麻豆剧果冻传媒星空视频| 校园H学长含着粉嫩小奶| 国精品无码人妻一区二区三区| 亚洲第一狼人伊人AV| 久久精品国产一区二区电影| 硬插人妻一区二区三区| 男人又粗又黑又硬的东西 | 一二三四视频社区3在线高清| 麻豆果冻视频传媒APP下载| 2019日韩中文字幕MV| 欧洲免费无码视频在线| 豆奶视频在线观看免费高清版| 熟妇高潮一区二区三区| 国产又爽又黄又刺激的视频 | 女高中生自慰污污网站| 宝贝腿开大点我添添公视频免费| 日产乱码一二三区别免费下载| 国产成人无码免费视频79| 亚洲AV中文无码乱人伦在线咪咕 | 粗大从后面狠狠贯穿H| 无码专区人妻诱中文字幕| 国产午夜成人精品视频APP| 亚洲婷婷五月激情综合APP| 男女作爱网站免费观看全过程| 超薄肉色丝袜一区二区| 无码人妻丝袜视频在线播免费| 狠狠躁夜夜躁人人爽碰AV| 亚洲国产欧美在线观看片不卡| 国产在线无码一区二区三区| 亚洲少妇XXXXX| 女口述第一次放进去的感受| 出租房里的交互高康张睿| 无码人妻一区二区三区四区AV | 欧精国精产品一区| 动物交配的全过程| 亚洲AV永久无码精品尤物在线| 老湿机香蕉久久久久久| 岳女四人共侍一夫婷婷| 狠狠躁日日躁夜夜躁2022麻豆| 曰韩无码无遮挡A级毛片| 日本久久久久久久久精品| 国产性天天综合网| 中文字幕亚洲无线码| 熟妇人妻久久中文字幕| 精品亚洲成在人线AV无码| 99精品视频在线观看婷婷| 无码成人免费AV片在线观看| 久久永久免费人妻精品我不卡| 成人午夜男女爽爽视频| 亚洲国产精品久久久久久| 欧美激情内射喷水高潮| 国产日产久久高清欧美一区| 中国熟妇内谢69XXXXX软件| 双方夫妻一起互动交流做| 久久精品国产亚洲AV果冻传媒| 超高级国王游戏电影| 亚洲欧美日韩精品成人| 日产2021免费一二三四| 精品无码国产AV一区二区三区| 成年大片免费视频播放|