배열과 슬라이스의 차이점: 1. 슬라이스는 포인터 유형이고 배열은 값 유형입니다. 2. 배열의 할당 형식은 값 전송이고 슬라이스의 할당 형식은 참조 전송입니다. , 슬라이스의 길이는 임의로 조정할 수 있습니다(슬라이스는 동적 배열입니다). 4. 배열의 길이는 고정되어 있지만 슬라이스 길이는 임의로 조정할 수 있습니다(슬라이스는 동적 배열입니다).
이 튜토리얼의 운영 환경: Windows 7 시스템, GO 버전 1.18, Dell G3 컴퓨터.
Go 언어의 배열은 C/C++의 배열과 거의 동일합니다. 크기가 고정되어 있으며 동적으로 확장할 수 없습니다. 크기가 초과되면 동적으로 확장할 수 있는 C++의 벡터와 거의 동일합니다. 용량이 줄어들면 메모리 블록을 다시 할당하고 데이터를 새 메모리 영역에 복사합니다. golang의 배열과 슬라이스를 더 잘 이해하기 위해 몇 가지 질문을 살펴보겠습니다.
Go의 슬라이스는 배열 위에 있는 추상적인 데이터 타입이므로 슬라이스를 이해하기 전에 먼저 배열을 이해해야 합니다.
해당 항목:
예:
var iarray1 [5]int32 var iarray2 [5]int32 = [5]int32{1, 2, 3, 4, 5} iarray3 := [5]int32{1, 2, 3, 4, 5} iarray4 := [5]int32{6, 7, 8, 9, 10} iarray5 := [...]int32{11, 12, 13, 14, 15} iarray6 := [4][4]int32{{1}, {1, 2}, {1, 2, 3}} fmt.Println(iarray1) fmt.Println(iarray2) fmt.Println(iarray3) fmt.Println(iarray4) fmt.Println(iarray5) fmt.Println(iarray6)
Result:
[0 0 0 0 0] [1 2 3 4 5] [1 2 3 4 5] [6 7 8 9 10] [11 12 13 14 15] [[1 0 0 0] [1 2 0 0] [1 2 3 0] [0 0 0 0]]
선언만 되었지만 할당되지 않은 배열 iarray1을 살펴봅니다. Go 언어는 자동으로 값을 0으로 할당합니다. iarray2와 iarray3을 다시 보면 Go 언어 선언이 유형을 나타낼 수 있는지 여부를 알 수 있습니다. var iarray3 = [5]int32{1, 2, 3, 4, 5}도 완전히 괜찮습니다.
어레이의 용량과 길이는 동일합니다. cap() 함수와 len() 함수는 모두 array
Array는 값 유형입니다. 한 배열을 다른 배열에 할당하면 복사본이 전달됩니다. 슬라이스는 참조 유형이지만, 슬라이스로 래핑된 배열을 슬라이스의 기본 배열이라고 합니다. 다음 예를 보세요:
//a是一个数组,注意数组是一个固定长度的,初始化时候必须要指定长度,不指定长度的话就是切片了 a := [3]int{1, 2, 3} //b是数组,是a的一份拷贝 b := a //c是切片,是引用类型,底层数组是a c := a[:] for i := 0; i < len(a); i++ { a[i] = a[i] + 1 } //改变a的值后,b是a的拷贝,b不变,c是引用,c的值改变 fmt.Println(a) //[2,3,4] fmt.Println(b) //[1 2 3] fmt.Println(c) //[2,3,4]
Go 언어에서 슬라이스는 가변 길이와 고정 용량을 가진 동일한 요소 시퀀스입니다. Go 언어에서 슬라이스의 본질은 배열입니다. 배열의 길이는 고정되어 있으므로 용량은 고정되어 있고, 슬라이스의 용량은 숨겨진 배열의 길이입니다. 가변 길이란 배열 길이 범위 내에서 가변적임을 의미합니다.
대응:
위의 해당 출력은 3), 4 )에서 해당 출력
[0 0 0 0 0] [0 0 0 0 0] [] [1 2 3 4 5]
입니다. 슬라이스 생성과 배열 생성의 유일한 차이점은 Type 앞의 "[]"에 숫자가 있는지 여부입니다. 비어 있으면 슬라이스를 나타내고, 그렇지 않으면 배열을 나타냅니다. 슬라이스에는 가변 길이가 있기 때문에
Go의 슬라이스는 배열 위에 있는 추상 데이터 유형이므로 생성된 슬라이스에는 항상 배열이 있습니다.
예:
slice0 := []string{"a", "b", "c", "d", "e"} slice1 := slice0[2 : len(slice0)-1] slice2 := slice0[:3] fmt.Println(slice0, slice1, slice2) slice2[2] = "8" fmt.Println(slice0, slice1, slice2)
출력:
[a b c d e] [c d] [a b c] [a b 8 d e] [8 d] [a b 8]
또한 슬라이스 슬라이스0, 슬라이스1 및 슬라이스2가 동일한 기본 배열에 대한 참조임을 보여줍니다. 따라서 슬라이스2가 변경되면 나머지 두 개도 변경됩니다
slice1 := make([]int, 2, 5) fmt.Println(len(slice1), cap(slice1)) for k := range slice1{ fmt.Println(&slice1[k]) } slice1 = append(slice1,4) fmt.Println(len(slice1), cap(slice1)) for k := range slice1{ fmt.Println(&slice1[k]) } slice1 = append(slice1,5,6,7) fmt.Println(len(slice1), cap(slice1)) for k := range slice1{ fmt.Println(&slice1[k]) }
2 5 //长度和容量 0xc420012150 0xc420012158 3 5 //第一次追加,未超出容量,所以内存地址未发生改变 0xc420012150 0xc420012158 0xc420012160 6 10 //第二次追加,超过容量,内存地址都发生了改变,且容量也发生了改变,且是原来的2倍 0xc4200100f0 0xc4200100f8 0xc420010100 0xc420010108 0xc420010110 0xc420010118
slice1 := make([]int, 2, 5) slice2 := slice1[:1] fmt.Println(len(slice1), cap(slice1)) for k := range slice1{ fmt.Println(&slice1[k]) } fmt.Println(len(slice2), cap(slice2)) for k := range slice2{ fmt.Println(&slice2[k]) } slice2 = append(slice2,4,5,6,7,8) fmt.Println(len(slice1), cap(slice1)) for k := range slice1{ fmt.Println(&slice1[k]) } fmt.Println(len(slice2), cap(slice2)) for k := range slice2{ fmt.Println(&slice2[k]) }
2 5 //slice1的长度和容量 0xc4200700c0 0xc4200700c8 1 5 //slice2的长度和容量 0xc4200700c0 2 5 //slice2追加后,slice1的长度和容量、内存都未发生改变 0xc4200700c0 0xc4200700c8 6 10 //slice2追加后,超过了容量,所以slice2的长度和容量、内存地址都发生改变。 0xc42007e000 0xc42007e008 0xc42007e010 0xc42007e018 0xc42007e020 0xc42007e028
1. 배열과 슬라이스의 할당 형태
예제 1arr1 := [3] int {1,2,3} arr2 := arr1 for k := range arr1 { fmt.Printf("%v ",&arr1[k]); } fmt.Println(""); for k := range arr2 { fmt.Printf("%v ",&arr2[k]); } fmt.Println("\n================="); slice1 := [] int{1,2,3} slice2 := slice1 for k := range slice1 { fmt.Printf("%v ",&slice1[k]); } fmt.Println(""); for k := range slice2 { fmt.Printf("%v ",&slice2[k]); } 输出结果: 0xc420014140 0xc420014148 0xc420014150 0xc420014160 0xc420014168 0xc420014170 ================= 0xc4200141a0 0xc4200141a8 0xc4200141b0 0xc4200141a0 0xc4200141a8 0xc4200141b0
배열의 할당은 값의 복사본이며, 이는 완전히 새로운 배열입니다. 슬라이스 할당은 참고 입니다. 또 다른 예를 살펴보겠습니다.
예제 2:arr1 := [3] int {1,2,3} arr2 := arr1 fmt.Printf("%v %v ",arr1,arr2); arr1[0] = 11 arr2[1] = 22 fmt.Printf("\n%v %v ",arr1,arr2); fmt.Println("\n================"); slice1 := [] int{1,2,3} slice2 := slice1 fmt.Printf("%v %v ",slice1,slice2); slice1[0] = 11 slice2[1] = 22 fmt.Printf("\n%v %v ",slice1,slice2); 输出结果: [1 2 3] [1 2 3] [11 2 3] [1 22 3] ================ [1 2 3] [1 2 3] [11 22 3] [11 22 3]
arr1 := [5] int {1,2,3} slice1 := arr1[0:3] slice2 := slice1[0:4] fmt.Printf("len: %d cap: %d %v\n",len(arr1),cap(arr1),arr1); //打印出非隐藏数组 for k := range arr1 { fmt.Printf("%v ",&arr1[k]); } fmt.Println(""); fmt.Printf("len: %d cap: %d %v\n",len(slice1),cap(slice1),slice1); //打印切片1 for k := range slice1 { fmt.Printf("%v ",&slice1[k]); } fmt.Println(""); fmt.Printf("len: %d cap: %d %v\n",len(slice2),cap(slice2),slice2); //打印切片2 for k := range slice2 { fmt.Printf("%v ",&slice2[k]); } fmt.Println("\n================="); arr1[0] = 11 //非隐藏数组、切片1、切片2各自发生更改 slice1[1] = 22 slice2[2] = 33 fmt.Printf("len: %d cap: %d %v\n",len(arr1),cap(arr1),arr1); //再次打印非隐藏数组 for k := range arr1 { fmt.Printf("%v ",&arr1[k]); } fmt.Println(""); fmt.Printf("len: %d cap: %d %v\n",len(slice1),cap(slice1),slice1); //再此打印切片1 for k := range slice1 { fmt.Printf("%v ",&slice1[k]); } fmt.Println(""); fmt.Printf("len: %d cap: %d %v\n",len(slice2),cap(slice2),slice2); //再次打印切片2 for k := range slice2 { fmt.Printf("%v ",&slice2[k]); } 输出结果: len: 5 cap: 5 [1 2 3 0 0]0xc420012150 0xc420012158 0xc420012160 0xc420012168 0xc420012170 len: 3 cap: 5 [1 2 3]0xc420012150 0xc420012158 0xc420012160 len: 4 cap: 5 [1 2 3 0]0xc420012150 0xc420012158 0xc420012160 0xc420012168 ================= len: 5 cap: 5 [11 22 33 0 0] 0xc420012150 0xc420012158 0xc420012160 0xc420012168 0xc420012170 len: 3 cap: 5 [11 22 33] 0xc420012150 0xc420012158 0xc420012160 len: 4 cap: 5 [11 22 33 0] 0xc420012150 0xc420012158 0xc420012160 0xc42001216
2. 배열은 매개변수로 사용되며 함수에 의해 호출됩니다.
func Connect() { arr1 := [5] int {1,2,3} fmt.Printf("%v ",arr1); for k := range arr1 { fmt.Printf("%v ",&arr1[k]); } fmt.Println(""); f1(arr1) fmt.Println(""); f2(&arr1) } func f1(arr [5]int) { fmt.Printf("%v ",arr); for k := range arr { fmt.Printf("%v ",&arr[k]); } } func f2(arr *[5]int) { fmt.Printf("%v ",arr); for k := range arr { fmt.Printf("%v ",&arr[k]); } } 输出结果: [1 2 3 0 0] 0xc420012150 0xc420012158 0xc420012160 0xc420012168 0xc420012170 [1 2 3 0 0] 0xc4200121b0 0xc4200121b8 0xc4200121c0 0xc4200121c8 0xc4200121d0 &[1 2 3 0 0] 0xc420012150 0xc420012158 0xc420012160 0xc420012168 0xc420012170
从上面的例子可以看出,数组在参数中,可以使用值传递和引用传递。值传递会拷贝新数组,引用传递则使用原数组。
func Connect() { slice1 := [] int {1,2,3} fmt.Printf("%v ",slice1); for k := range slice1 { fmt.Printf("%v ",&slice1[k]); } fmt.Println(""); f1(slice1) } func f1(slice []int) { fmt.Printf("%v ",slice); for k := range slice { fmt.Printf("%v ",&slice[k]); } } 输出结果: [1 2 3] 0xc420014140 0xc420014148 0xc420014150 [1 2 3] 0xc420014140 0xc420014148 0xc42001415
从这个例子中可以看出,切片在参数中传递本身就引用。
总结:
切片是指针类型,数组是值类型
数组的赋值形式为值传递,切片的赋值形式为引用传递
数组的长度是固定的,而切片长度可以任意调整(切片是动态的数组)
数组只有长度一个属性,而切片比数组多了一个容量(cap)属性
위 내용은 Go 언어에서 배열과 슬라이스의 차이점은 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!