網(wǎng)站首頁(yè) 編程語(yǔ)言 正文
golang數(shù)組和切片作為參數(shù)和返回值的實(shí)現(xiàn)_Golang
作者:weixin_44387482 ? 更新時(shí)間: 2022-04-15 編程語(yǔ)言1. 數(shù)組作為參數(shù)和返回值時(shí)
1.1數(shù)組的定義
數(shù)組是具有相同唯一類(lèi)型的一組已編號(hào)且長(zhǎng)度固定的數(shù)據(jù)項(xiàng)序列,這種類(lèi)型可以是任意的原始類(lèi)型例如整型、字符串或者自定義類(lèi)型
var arr [10]int //定義長(zhǎng)度為10的類(lèi)型是int的數(shù)組arr arr[0] = 1 // 數(shù)組的下標(biāo)從0開(kāi)始 數(shù)組的賦值 var arr1 = [5]int{1,2,3,4,5} //數(shù)組的初始化的定義方式 arr2 := [5]int{1,2,3,4,5} //同上 arr3 := [...]int{1,2,3,4,5} //編譯器通過(guò)元素個(gè)數(shù)自動(dòng)推斷數(shù)組的長(zhǎng)度
1.2數(shù)組作為參數(shù)和返回值的時(shí)候
func GetArray(arr [5]int)(v [5]int){ ?? ?fmt.Printf("GetArray arr===%v, %p\n", arr,&arr) // 查看傳進(jìn)來(lái)的參數(shù)和地址 ?? ?arr[1] = 3 //修改其中的一個(gè)值 ?? ?return arr } func main(){ ?? ?arr :=[...]int{1,2,3,4,5} ?// 定義一個(gè)長(zhǎng)度為5 類(lèi)型是int的數(shù)組 ?? ?fmt.Printf("main arr=%v, %p\n", arr, &arr) ?? ?value := GetArray(arr) ?? ?fmt.Printf("main GetArray value=%v, %p, arr=%v,%p\n", value, &value,arr, &arr) }
輸出結(jié)果:
main arr=[1 2 3 4 5], 0xc000012390
GetArray arr===[1 2 3 4 5], 0xc000012420
main GetArray value=[1 3 3 4 5], 0xc0000123f0, arr=[1 2 3 4 5],0xc000012390
從上面的輸出結(jié)果來(lái)看 當(dāng)使用數(shù)組作為參數(shù)和返回值的時(shí)候,傳進(jìn)去的是值,在函數(shù)內(nèi)部對(duì)數(shù)組進(jìn)行修改并不會(huì)影響原數(shù)據(jù)
2.切片作為參數(shù)和返回值
2.1 切片的定義初始化
Go 語(yǔ)言切片是對(duì)數(shù)組的抽象。
Go 數(shù)組的長(zhǎng)度不可改變,在特定場(chǎng)景中這樣的集合就不太適用,Go 中提供了一種靈活,功能強(qiáng)悍的內(nèi)置類(lèi)型切片(“動(dòng)態(tài)數(shù)組”),與數(shù)組相比切片的長(zhǎng)度是不固定的,可以追加元素,在追加時(shí)可能使切片的容量增大。
var myslice []int ?//定義一個(gè)切片 所有的數(shù)據(jù)類(lèi)型都是int 切片與數(shù)組的定義差別是可以不帶長(zhǎng)度 var myslice []int = make([]int ,5) //定義一個(gè)長(zhǎng)度為5的切片? myslice1 := make([]int,5) //同上? make([]T, length, capacity) //定義的參數(shù)分別是類(lèi)型,長(zhǎng)度,容量(可選) myslice2 :=[] int {1,2,3 } ? //切片初始化 myarr := [...]int{1,2,3,4,5}? myslice3 := myarr[1:3] //也可以先定義一個(gè)數(shù)組 然后截取這里是從下標(biāo)1開(kāi)始到下標(biāo)為3(不包含)
ps:當(dāng)我們通過(guò)從數(shù)組截取獲得切片的時(shí)候,我們可以發(fā)現(xiàn)截取后的切片和原來(lái)的數(shù)組是共用數(shù)據(jù)源的,如果修改原來(lái)的數(shù)組數(shù)據(jù)源 那么通過(guò)截取數(shù)組得到的切片的值也會(huì)被修改反之亦然
func main(){ ?? ?arr :=[...]int{1,2,3,4,5} ?// 定義一個(gè)長(zhǎng)度為5 類(lèi)型是int的數(shù)組 ?? ?myslice1 := arr[0:3] //切片獲取下標(biāo)[0,3)的值 ?? ?myslice2 := arr[0:4] //切片獲取下標(biāo)[1,4)的值 ?? ?fmt.Printf("myslice1=%v, ppp=%p\n", myslice1, &myslice1) ?? ?fmt.Printf("myslice2=%v, ppp=%p\n", myslice2, &myslice2) ?? ?arr[1] = 666 //修改數(shù)組的值 ?? ?fmt.Printf("After myslice1=%v, ppp=%p\n", myslice1, &myslice1) ?? ?fmt.Printf("After myslice2=%v, ppp=%p\n", myslice2, &myslice2) ?? ?myslice2[2] =777 //修改切片的值 ?? ?fmt.Printf("arr=%v", arr) }
輸出的結(jié)果:
myslice1=[1 2 3], ppp=0xc000004078
myslice2=[1 2 3 4], ppp=0xc000004090
After myslice1=[1 666 3], ppp=0xc000004078
After myslice2=[1 666 3 4], ppp=0xc000004090
arr=[1 666 777 4 5]
2.2 切片的存儲(chǔ)大致分為3部分
一部分是存的指向匿名數(shù)組的指針,一個(gè)是長(zhǎng)度,一個(gè)是容量,我們?cè)诙x切片的時(shí)候 會(huì)在底層保存一個(gè)匿名的數(shù)組,通過(guò)上面的數(shù)組得到切片的方式得出的結(jié)論 當(dāng)我們通過(guò)一個(gè)切片得到另一個(gè)切片的時(shí)候我們的數(shù)據(jù)源也是共享的
2.3 切片作為參數(shù)和返回值
func GetSlice(myslice []int)(value []int){ ?? ?fmt.Printf("GetSlice myslice===%v, ppppp=%p\n", myslice,&myslice) // 查看傳進(jìn)來(lái)的參數(shù)和地址 ?? ?myslice[2] = 10 ?? ?return myslice } func main(){ ?? ?var myslice []int //定義一個(gè)空的切片 ?? ?myslice = append(myslice, 1) ?? ?myslice = append(myslice, 2) ?? ?myslice = append(myslice, 3) ?? ?myslice = append(myslice, 4) ?? ?myslice = append(myslice, 5) //向切片里面追加元素 ?? ?fmt.Printf("myslice ==%v ppp=%p\n", myslice, &myslice) ?? ?rslice := GetSlice(myslice) ?? ?fmt.Printf("rslice==%v ppp=%p, myslice==%v,ppp=%p\n", rslice,&rslice,myslice,&myslice) }
輸出結(jié)果:
myslice ==[1 2 3 4 5] ppp=0xc000004078
GetSlice myslice===[1 2 3 4 5], ppppp=0xc0000040c0
rslice==[1 2 10 4 5] ppp=0xc0000040a8, myslice==[1 2 10 4 5],ppp=0xc000004078
結(jié)論:從上面的輸出的結(jié)果和地址來(lái)看,當(dāng)切片作為參數(shù)的時(shí)候穿進(jìn)去的是值,也就是值傳遞,但是當(dāng)我在函數(shù)里面修改切片的時(shí)候,我們發(fā)現(xiàn)源數(shù)據(jù)也會(huì)被修改,這是因?yàn)槲覀冊(cè)谇衅牡讓泳S護(hù)這一個(gè)匿名的數(shù)組,當(dāng)我們把切片當(dāng)成參數(shù)的時(shí)候,會(huì)重現(xiàn)創(chuàng)建一個(gè)切片,但是創(chuàng)建的這個(gè)切片和我們?cè)瓉?lái)的數(shù)據(jù)是共享數(shù)據(jù)源的,所以在函數(shù)內(nèi)被修改,源數(shù)據(jù)也會(huì)被修改
2.4 append 切片動(dòng)態(tài)增長(zhǎng)的原理
golang提供了append 函數(shù)向切片中增加元素,但是切片和數(shù)組一樣也是有長(zhǎng)度的,如果添加的元素個(gè)數(shù)剛好在長(zhǎng)度范圍內(nèi),就直接在末尾添加元素,但是如果添加的元素的個(gè)數(shù)超過(guò)了長(zhǎng)度之后,就需要對(duì)底層的數(shù)組進(jìn)行擴(kuò)容了,這個(gè)新的數(shù)組的長(zhǎng)度是原來(lái)的兩倍 ,而創(chuàng)建這個(gè)新的數(shù)組之后我們將新的數(shù)組的指針保存到切片數(shù)據(jù)中,就這樣我們實(shí)現(xiàn)了切片的動(dòng)態(tài)增長(zhǎng),而當(dāng)切片作為參數(shù)的時(shí)候,如果我們?cè)诤瘮?shù)里使用append函數(shù)增加元素,且元素的個(gè)數(shù)超過(guò)長(zhǎng)度的話 在函數(shù)中我們就會(huì)創(chuàng)建除一個(gè)新的切片這個(gè)時(shí)候我們?cè)诤瘮?shù)內(nèi)對(duì)新的切片進(jìn)行修改 就不會(huì)影響到原來(lái)的切片了
func GetSlice(myslice []int)(value []int){ ?? ?fmt.Printf("GetSlice myslice===%v, ppppp=%p\n", myslice,&myslice) // 查看傳進(jìn)來(lái)的參數(shù)和地址 ?? ?myslice = append(myslice, 6) ?? ?return myslice } func main(){ ?? ?myslice := make([]int,5) ?//定義長(zhǎng)度為5 類(lèi)型是int的切片 ?? ?for i:=0; i< len(myslice);i++{ ?? ??? ?myslice[i] = i+1 ?? ?} ?? ?fmt.Printf("myslice ==%v ppp=%p\n", myslice, &myslice) ?? ?rslice := GetSlice(myslice) ?? ?fmt.Printf("rslice==%v ppp=%p, myslice==%v,ppp=%p\n", rslice,&rslice,myslice,&myslice) }
輸出結(jié)果:
myslice ==[1 2 3 4 5] ppp=0xc000004078
GetSlice myslice===[1 2 3 4 5], ppppp=0xc0000040c0
rslice==[1 2 3 4 5 6] ppp=0xc0000040a8, myslice==[1 2 3 4 5],ppp=0xc000004078
2.5 copy 函數(shù) 通過(guò)賦值切片可以使得兩個(gè)切片的數(shù)據(jù)不共享
func main(){ ?? ?myslice := make([]int,5) ?//定義長(zhǎng)度為5 類(lèi)型是int的切片 ?? ?for i:=0; i< len(myslice);i++{ ?? ??? ?myslice[i] = i+1 ?? ?} ?? ?fmt.Printf("myslice ==%v ppp=%p\n", myslice, &myslice) ?? ?copymyslice := make([]int,5) ?? ?copy(copymyslice, myslice) ?? ?myslice[4] = 10 ?? ?fmt.Printf("copymyslice ==%v myslice=%v\n", copymyslice, myslice) }
輸出結(jié)果:
myslice ==[1 2 3 4 5] ppp=0xc000004078
copymyslice ==[1 2 3 4 5] myslice=[1 2 3 4 10]
結(jié)論:使用copy函數(shù)對(duì)切片進(jìn)行賦值的時(shí)候可以避免源數(shù)據(jù)與目標(biāo)數(shù)據(jù)共享底層數(shù)組
3. 總結(jié):
數(shù)組還是切片,在函數(shù)中傳遞的時(shí)候如果沒(méi)有指定為指針傳遞的話,都是值傳遞,但是切片在傳遞的過(guò)程中,有著共享底層數(shù)組的風(fēng)險(xiǎn),所以如果在函數(shù)內(nèi)部進(jìn)行了更改的時(shí)候,會(huì)修改到源數(shù)據(jù),所以我們需要根據(jù)不同的需求來(lái)處理,如果我們不希望源數(shù)據(jù)被修改話的我們可以使用copy函數(shù)復(fù)制切片后再傳入,如果希望源數(shù)據(jù)被修改的話我們應(yīng)該使用指針傳遞的方式
原文鏈接:https://blog.csdn.net/weixin_44387482/article/details/119763558
相關(guān)推薦
- 2022-07-18 數(shù)據(jù)結(jié)構(gòu) III 深入理解棧和隊(duì)列實(shí)現(xiàn)
- 2022-09-22 k8s 存儲(chǔ)卷之 PV & PVC
- 2022-05-17 Error running ‘myToncat‘: Address localhost:8080 i
- 2022-07-26 Python使用shutil操作文件、subprocess運(yùn)行子程序_python
- 2022-07-10 python日志管理loguru模塊實(shí)操
- 2022-08-29 Python可視化神器pyecharts之繪制箱形圖_python
- 2023-01-02 Python創(chuàng)建相同值數(shù)組/列表的兩種方法_python
- 2022-06-25 PyTorch模型保存與加載實(shí)例詳解_python
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過(guò)濾器
- Spring Security概述快速入門(mén)
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支