網站首頁 編程語言 正文
1. 數組作為參數和返回值時
1.1數組的定義
數組是具有相同唯一類型的一組已編號且長度固定的數據項序列,這種類型可以是任意的原始類型例如整型、字符串或者自定義類型
var arr [10]int //定義長度為10的類型是int的數組arr arr[0] = 1 // 數組的下標從0開始 數組的賦值 var arr1 = [5]int{1,2,3,4,5} //數組的初始化的定義方式 arr2 := [5]int{1,2,3,4,5} //同上 arr3 := [...]int{1,2,3,4,5} //編譯器通過元素個數自動推斷數組的長度
1.2數組作為參數和返回值的時候
func GetArray(arr [5]int)(v [5]int){ ?? ?fmt.Printf("GetArray arr===%v, %p\n", arr,&arr) // 查看傳進來的參數和地址 ?? ?arr[1] = 3 //修改其中的一個值 ?? ?return arr } func main(){ ?? ?arr :=[...]int{1,2,3,4,5} ?// 定義一個長度為5 類型是int的數組 ?? ?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) }
輸出結果:
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
從上面的輸出結果來看 當使用數組作為參數和返回值的時候,傳進去的是值,在函數內部對數組進行修改并不會影響原數據
2.切片作為參數和返回值
2.1 切片的定義初始化
Go 語言切片是對數組的抽象。
Go 數組的長度不可改變,在特定場景中這樣的集合就不太適用,Go 中提供了一種靈活,功能強悍的內置類型切片(“動態數組”),與數組相比切片的長度是不固定的,可以追加元素,在追加時可能使切片的容量增大。
var myslice []int ?//定義一個切片 所有的數據類型都是int 切片與數組的定義差別是可以不帶長度 var myslice []int = make([]int ,5) //定義一個長度為5的切片? myslice1 := make([]int,5) //同上? make([]T, length, capacity) //定義的參數分別是類型,長度,容量(可選) myslice2 :=[] int {1,2,3 } ? //切片初始化 myarr := [...]int{1,2,3,4,5}? myslice3 := myarr[1:3] //也可以先定義一個數組 然后截取這里是從下標1開始到下標為3(不包含)
ps:當我們通過從數組截取獲得切片的時候,我們可以發現截取后的切片和原來的數組是共用數據源的,如果修改原來的數組數據源 那么通過截取數組得到的切片的值也會被修改反之亦然
func main(){ ?? ?arr :=[...]int{1,2,3,4,5} ?// 定義一個長度為5 類型是int的數組 ?? ?myslice1 := arr[0:3] //切片獲取下標[0,3)的值 ?? ?myslice2 := arr[0:4] //切片獲取下標[1,4)的值 ?? ?fmt.Printf("myslice1=%v, ppp=%p\n", myslice1, &myslice1) ?? ?fmt.Printf("myslice2=%v, ppp=%p\n", myslice2, &myslice2) ?? ?arr[1] = 666 //修改數組的值 ?? ?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) }
輸出的結果:
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 切片的存儲大致分為3部分
一部分是存的指向匿名數組的指針,一個是長度,一個是容量,我們在定義切片的時候 會在底層保存一個匿名的數組,通過上面的數組得到切片的方式得出的結論 當我們通過一個切片得到另一個切片的時候我們的數據源也是共享的
2.3 切片作為參數和返回值
func GetSlice(myslice []int)(value []int){ ?? ?fmt.Printf("GetSlice myslice===%v, ppppp=%p\n", myslice,&myslice) // 查看傳進來的參數和地址 ?? ?myslice[2] = 10 ?? ?return myslice } func main(){ ?? ?var myslice []int //定義一個空的切片 ?? ?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) }
輸出結果:
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
結論:從上面的輸出的結果和地址來看,當切片作為參數的時候穿進去的是值,也就是值傳遞,但是當我在函數里面修改切片的時候,我們發現源數據也會被修改,這是因為我們在切片的底層維護這一個匿名的數組,當我們把切片當成參數的時候,會重現創建一個切片,但是創建的這個切片和我們原來的數據是共享數據源的,所以在函數內被修改,源數據也會被修改
2.4 append 切片動態增長的原理
golang提供了append 函數向切片中增加元素,但是切片和數組一樣也是有長度的,如果添加的元素個數剛好在長度范圍內,就直接在末尾添加元素,但是如果添加的元素的個數超過了長度之后,就需要對底層的數組進行擴容了,這個新的數組的長度是原來的兩倍 ,而創建這個新的數組之后我們將新的數組的指針保存到切片數據中,就這樣我們實現了切片的動態增長,而當切片作為參數的時候,如果我們在函數里使用append函數增加元素,且元素的個數超過長度的話 在函數中我們就會創建除一個新的切片這個時候我們在函數內對新的切片進行修改 就不會影響到原來的切片了
func GetSlice(myslice []int)(value []int){ ?? ?fmt.Printf("GetSlice myslice===%v, ppppp=%p\n", myslice,&myslice) // 查看傳進來的參數和地址 ?? ?myslice = append(myslice, 6) ?? ?return myslice } func main(){ ?? ?myslice := make([]int,5) ?//定義長度為5 類型是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) }
輸出結果:
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 函數 通過賦值切片可以使得兩個切片的數據不共享
func main(){ ?? ?myslice := make([]int,5) ?//定義長度為5 類型是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) }
輸出結果:
myslice ==[1 2 3 4 5] ppp=0xc000004078
copymyslice ==[1 2 3 4 5] myslice=[1 2 3 4 10]
結論:使用copy函數對切片進行賦值的時候可以避免源數據與目標數據共享底層數組
3. 總結:
數組還是切片,在函數中傳遞的時候如果沒有指定為指針傳遞的話,都是值傳遞,但是切片在傳遞的過程中,有著共享底層數組的風險,所以如果在函數內部進行了更改的時候,會修改到源數據,所以我們需要根據不同的需求來處理,如果我們不希望源數據被修改話的我們可以使用copy函數復制切片后再傳入,如果希望源數據被修改的話我們應該使用指針傳遞的方式
原文鏈接:https://blog.csdn.net/weixin_44387482/article/details/119763558
相關推薦
- 2022-10-22 Python常用工具類之adbtool示例代碼_python
- 2023-02-02 Python實現自動生成請假條_python
- 2023-09-17 ES常見錯誤總結
- 2024-03-04 新版ECharts實現“暫無數據”的完美解決方案
- 2022-07-12 ERROR:ORA-12543: TNS:destination host unreachable
- 2022-06-01 C++構造函數的類型,淺拷貝與深拷貝詳解_C 語言
- 2022-03-23 C語言實現貪吃蛇小黑窗_C 語言
- 2022-06-18 C#使用ThreadPriority設置線程優先級_C#教程
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支