Maison >développement back-end >Golang >Quelle est la différence entre les tableaux et les tranches en langage Go ?

Quelle est la différence entre les tableaux et les tranches en langage Go ?

青灯夜游
青灯夜游original
2023-01-13 17:26:468277parcourir

La différence entre les tableaux et les tranches : 1. Les tranches sont des types de pointeurs, les tableaux sont des types de valeurs ; 2. La forme d'affectation des tableaux est un transfert de valeur et la forme d'affectation des tranches est un transfert de référence ; , tandis que la longueur des tranches peut être ajustée arbitrairement (les tranches sont des tableaux dynamiques); 4. La longueur du tableau est fixe, mais la longueur des tranches peut être ajustée arbitrairement (les tranches sont des tableaux dynamiques).

Quelle est la différence entre les tableaux et les tranches en langage Go ?

L'environnement d'exploitation de ce tutoriel : système Windows 7, GO version 1.18, ordinateur Dell G3.

Les tableaux en langage Go sont à peu près équivalents aux tableaux en C/C++, qui sont de taille fixe et ne peuvent pas être étendus dynamiquement. Les tranches sont à peu près équivalentes aux vecteurs en C++, dont la taille peut être étendue dynamiquement lorsque la taille dépasse. la capacité, il s'agit de ré-allouer un bloc de mémoire et de copier les données dans la nouvelle zone mémoire. Passons en revue quelques questions pour mieux comprendre les tableaux et les tranches de Golang.

1. Tableau

La tranche de Go est un type de données abstrait au-dessus du tableau, vous devez donc d'abord comprendre le tableau avant de comprendre la tranche.

1. Trois façons de déclarer des tableaux

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

correspondant à :

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

Exemple :

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)

Résultat :

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

Nous regardons le tableau iarray1, qui est uniquement déclaré mais non attribué. Le langage Go nous attribue automatiquement la valeur 0. En regardant à nouveau iarray2 et iarray3, nous pouvons voir que la déclaration du langage Go peut indiquer le type ou non var iarray3 = [5]int32{1, 2, 3, 4, 5} est également tout à fait correct.

2. La capacité et la longueur du tableau

La capacité et la longueur du tableau sont les mêmes. La fonction cap() et la fonction len() génèrent la capacité (c'est-à-dire la longueur) du tableau

3. Type

Les tableaux sont des types de valeur lors de l'attribution d'un tableau à un autre tableau, une copie est transmise. Bien que les tranches soient des types référence, le tableau enveloppé par la tranche est appelé le tableau sous-jacent de la tranche. Regardez l'exemple suivant :

//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. Découpage

En langage Go, une tranche est une séquence identique d'éléments de longueur variable et de capacité fixe. L'essence de slice dans le langage Go est un tableau. La capacité est fixe car la longueur du tableau est fixe et la capacité de la tranche est la longueur du tableau caché. La longueur variable fait référence au fait d'être variable dans la plage de longueur du tableau.

1. Quatre façons de créer des tranches

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

En conséquence :

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

La sortie correspondante ci-dessus

[0 0 0 0 0]
[0 0 0 0 0]
[]
[1 2 3 4 5]

de 3), 4) Il peut On voit que la seule différence entre la création d'une tranche et la création d'un tableau est de savoir s'il y a un nombre dans le "[]" avant Type. S'il est vide, il représente une tranche, sinon il représente un tableau. Parce que les tranches ont des longueurs variables

2. Les tableaux cachés

Les tranches de Go sont des types de données abstraits au-dessus des tableaux, donc les tranches créées ont toujours un tableau.

Exemple :

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)

Sortie :

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

Cela montre également que les tranches slice0, slice1 et slice2 sont des références au même tableau sous-jacent, donc si slice2 change, les deux autres changeront

3.

La fonction intégrée append peut ajouter une ou plusieurs autres valeurs du même type à une tranche. Si le nombre d’éléments ajoutés dépasse la capacité de la tranche d’origine, ce qui est finalement renvoyé est une toute nouvelle tranche dans un tout nouveau tableau. S'il ne dépasse pas, ce qui est finalement renvoyé est une toute nouvelle tranche dans le tableau d'origine. Dans tous les cas, append n’a aucun effet sur la tranche d’origine.

Exemple :

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

Sortie :

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

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

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

Regardez un autre exemple :

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

La sortie ci-dessus :

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. La différence entre les tableaux et les tranches dans GO

Ce qui suit examine principalement quelques exemples pratiques pour illustrer les tableaux. et La différence de découpage.

1. Formulaire d'affectation de tableaux et de tranches

Exemple 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

Comme le montre cet exemple,

L'affectation d'un tableau est une copie de la valeur, qui est un tout nouveau tableau. L'affectation de la tranche est une référence . Regardons un autre exemple.

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

Cet exemple illustre encore une fois : les tableaux sont des affectations et des copies, tandis que les tranches ne sont que des références. Les déclarations slice des exemples 1 et 2 utilisent des tableaux cachés. Regardons à nouveau l'exemple 3, en utilisant un tableau non masqué.

Exemple 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

Pour résumer les trois exemples ci-dessus, on peut voir que les tranches sont des références à des tableaux, y compris des références à des tableaux cachés et des tableaux non cachés.

2. Le tableau est utilisé comme paramètre et est appelé par la fonction

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

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn