Heim  >  Artikel  >  Backend-Entwicklung  >  Was ist der Unterschied zwischen Arrays und Slices in der Go-Sprache?

Was ist der Unterschied zwischen Arrays und Slices in der Go-Sprache?

青灯夜游
青灯夜游Original
2023-01-13 17:26:468170Durchsuche

Der Unterschied zwischen Arrays und Slices: 1. Slices sind Zeigertypen, Arrays sind Werttypen; 2. Die Zuweisungsform von Arrays ist die Wertübertragung und die Zuweisungsform von Slices ist die Referenzübertragung. 3. Die Länge von Arrays ist festgelegt , während die Länge der Slices beliebig angepasst werden kann (Slices sind dynamische Arrays); 4. Die Länge des Arrays ist fest, aber die Slice-Länge kann beliebig angepasst werden (Slices sind dynamische Arrays).

Was ist der Unterschied zwischen Arrays und Slices in der Go-Sprache?

Die Betriebsumgebung dieses Tutorials: Windows 7-System, GO Version 1.18, Dell G3-Computer.

Arrays in der Go-Sprache entsprechen in etwa den Arrays in C/C++. Sie haben eine feste Größe und können nicht dynamisch erweitert werden. Das Slicing entspricht in etwa dem Vektor in C++, dessen Größe dynamisch erweitert werden kann Wenn die Kapazität zu hoch ist, wird ein Speicherblock neu zugewiesen und die Daten in den neuen Speicherbereich kopiert. Lassen Sie uns ein paar Fragen durchgehen, um die Arrays und Slices von Golang besser zu verstehen.

1. Array

Gos Slice ist ein abstrakter Datentyp über dem Array. Sie müssen also zuerst das Array verstehen, bevor Sie das Slice verstehen.

1. Drei Möglichkeiten, Arrays zu deklarieren. value2, … , valueN}

    entsprechend:
  • identifier := [len]type{}
  • identifier := [len]type{value1, value2, … , valueN}
identifier := [ …] type{value1, value2, …, valueN}

    Beispiel:
  • 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)
  • Ergebnis:
  • [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]]
  • Wir schauen uns das Array iarray1 an, das nur deklariert, aber nicht zugewiesen ist. Die Go-Sprache weist uns automatisch den Wert 0 zu. Wenn wir uns iarray2 und iarray3 noch einmal ansehen, können wir sehen, dass die Go-Sprachdeklaration auch den Typ var iarray3 = [5]int32{1, 2, 3, 4, 5} angeben kann.
2. Die Kapazität und Länge des Arrays

Die Kapazität und Länge des Arrays sind gleich. Sowohl die Funktion cap() als auch die Funktion len() geben die Kapazität (d. h. die Länge) des Arrays aus

3. Bei der Zuweisung eines Arrays zu einem anderen Array wird eine Kopie übergeben. Während es sich bei Slices um Referenztypen handelt, wird das vom Slice umschlossene Array als das zugrunde liegende Array des Slice bezeichnet. Schauen Sie sich das folgende Beispiel an:

//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]

2. Slicing

In der Go-Sprache ist ein Slice eine identische Folge von Elementen mit variabler Länge und fester Kapazität. Die Essenz von Slice in der Go-Sprache ist ein Array. Die Kapazität ist fest, da die Länge des Arrays fest ist und die Kapazität des Slice der Länge des verborgenen Arrays entspricht. Variable Länge bedeutet, dass sie innerhalb des Bereichs der Array-Länge variabel ist.

1. Vier Möglichkeiten, Slices zu erstellen

var Slice1 = make([]int,5,10)

var Slice2 = make([]int,5)

var Slice3 = []int{ }

var Slice4 = []int{1,2,3,4,5}

    Entsprechend:
  • slice1 := make([]int,5,10)
  • slice2 := make( []int ,5)
  • slice3 := []int{}
slice4 := []int{1,2,3,4,5}

    Die obige entsprechende Ausgabe
  • [0 0 0 0 0]
    [0 0 0 0 0]
    []
    [1 2 3 4 5]
  • von 3), 4 ) Es kann Es ist ersichtlich, dass der einzige Unterschied zwischen der Erstellung eines Slice und der Erstellung eines Arrays darin besteht, ob im „[]“ vor dem Typ eine Zahl steht. Wenn es leer ist, stellt es ein Slice dar, andernfalls stellt es ein Array dar. Weil Slices variable Längen haben
  • 2. Versteckte Arrays
  • Gos Slices sind abstrakte Datentypen über Arrays, sodass die erstellten Slices immer ein Array haben.

Beispiel:

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)

Ausgabe:

[a b c d e] [c d] [a b c]
[a b 8 d e] [8 d] [a b 8]

Es zeigt auch, dass die Slices Slice0, Slice1 und Slice2 Verweise auf dasselbe zugrunde liegende Array sind. Wenn sich also Slice2 ändert, ändern sich auch die anderen beiden

3

Die integrierte Funktion append kann einen oder mehrere andere Werte desselben Typs an ein Slice anhängen. Wenn die Anzahl der angehängten Elemente die Kapazität des ursprünglichen Slice überschreitet, wird letztendlich ein brandneuer Slice in einem brandneuen Array zurückgegeben. Wenn der Wert nicht überschritten wird, wird letztendlich ein brandneues Slice im ursprünglichen Array zurückgegeben. In jedem Fall hat das Anhängen keine Auswirkung auf das Original-Slice.

Beispiel:

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])
}

Ausgabe:

2 5 //长度和容量
0xc420012150
0xc420012158

3 5 //第一次追加,未超出容量,所以内存地址未发生改变
0xc420012150
0xc420012158
0xc420012160

6 10 //第二次追加,超过容量,内存地址都发生了改变,且容量也发生了改变,且是原来的2倍
0xc4200100f0
0xc4200100f8
0xc420010100
0xc420010108
0xc420010110
0xc420010118

Sehen Sie sich ein anderes Beispiel an:

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])
}
Die obige Ausgabe:
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

3. Der Unterschied zwischen Arrays und Slices in GO

Im Folgenden werden hauptsächlich einige praktische Beispiele zur Veranschaulichung von Arrays betrachtet und Der Unterschied beim Schneiden.

1. Zuweisungsformen von Arrays und Slices

Beispiel 1

arr1 := [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

Wie aus diesem Beispiel ersichtlich ist,

Die Zuweisung eines Arrays ist eine Kopie des Werts, der ein brandneues Array ist. Die Zuordnung des Slice ist eine Referenz

. Schauen wir uns ein anderes Beispiel an.

Beispiel 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]

Dieses Beispiel verdeutlicht noch einmal: Arrays sind Zuweisungen und Kopien, während Slices nur Referenzen sind. Die Slice-Deklarationen in den Beispielen 1 und 2 verwenden versteckte Arrays. Schauen wir uns Beispiel 3 noch einmal an und verwenden dabei ein nicht ausgeblendetes Array.


Beispiel 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
Um die obigen drei Beispiele zusammenzufassen, ist ersichtlich, dass Slices Verweise auf Arrays sind, einschließlich Verweise auf versteckte Arrays und nicht versteckte Arrays.

2. Das Array wird als Parameter verwendet und von der Funktion aufgerufen

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视频教程编程教学

Das obige ist der detaillierte Inhalt vonWas ist der Unterschied zwischen Arrays und Slices in der Go-Sprache?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn