Maison > développement back-end > Golang > GO STIPES ET SOMBRE: Comprendre la mémoire partagée et éviter `APPEND () 'Pièges

GO STIPES ET SOMBRE: Comprendre la mémoire partagée et éviter `APPEND () 'Pièges

Barbara Streisand
Libérer: 2025-01-29 00:21:10
original
918 Les gens l'ont consulté

Go Slices and Subslices: Understanding Shared Memory and Avoiding `append()` Pitfalls

dans -depth compréhension du découpage du langage go: mémoire partagée et

piège append() Salut tout le monde! Bienvenue sur mon blog. ? Si vous êtes ici, vous êtes peut-être entré en contact avec Golang, ou que vous êtes un développeur expérimenté, et vous voulez comprendre le principe de travail interne de la section. Alors commençons!

Le langage GO est très apprécié en raison de sa simplicité et de son efficacité - comme les gens disent souvent: "Le langage Go est de terminer le travail." Pour les développeurs de C, C ou Java et d'autres langues, la grammaire simple et la facilité d'utilisation du langage Go sont rafraîchissantes. Cependant, même dans le langage Go, certaines caractéristiques peuvent confondre les développeurs, en particulier lors du traitement des tranches et des sous-licences. Débournions ces subtilités et comprenons mieux comment éviter les pièges communs de

et tranchés pour partager la mémoire.

append() Quelle est la tranche dans la langue go?

Habituellement, lorsque vous avez besoin d'une structure de données pour stocker une série de valeurs, le tranchage est le premier choix en langue go. Leur flexibilité vient d'un tel fait: leur longueur ne fait pas partie de son type. Cette fonctionnalité surmonte les restrictions du tableau, nous permettant de créer une fonction unique qui peut gérer toutes les tranches et permet à la tranche d'augmenter ou de se développer en fonction des besoins. Bien que la tranche ait des similitudes avec le tableau, telles que l'indexation et la longueur, elles ont différentes méthodes de gestion des données. Slice agit comme une référence au tableau sous-jacent, qui stocke en fait les données des tranches. Essentiellement, la tranche offre une vue de certains ou tous les éléments du tableau. Par conséquent, lorsque vous créez une tranche, GO traitera automatiquement le tableau inférieur de la création d'éléments / données en tranches.

La mémoire partagée des tranchés

Le tableau est un bloc de mémoire continu, mais ce qui rend la tranche intéressante, c'est comment ils citent cette mémoire. Décomposons la structure de la tranche:

Lorsque vous créez une tranche, il contient trois composants:

Poèmes pointant vers le tableau sous-jacent
type slice struct {
    array unsafe.Pointer // 指向底层数组的指针
    len   int           // 切片中的元素数量
    cap   int           // 底层数组的容量
}
Copier après la connexion
Copier après la connexion
Copier après la connexion

<切> la longueur du tranchage (le nombre d'éléments qu'il contient)

    <量> Capacité (le nombre d'éléments qu'il peut contenir avant la nécessité d'augmenter)
  1. C'est là que les choses deviennent intéressantes. Si vous avez plusieurs tranches dérivées du même tableau, les modifications apportées par une tranche se refléteront dans d'autres tranches car elles partagent le même tableau sous-jacent. len
  2. Voyons l'exemple suivant:
  3. cap
  4. <解> Comprendre la capacité de tranchage

Avant d'approfondir davantage, essayons de comprendre la capacité de tranchage

. Lorsque vous obtenez des sous-licences à partir du découpage existant de la langue GO, la capacité

package main

import "fmt"

func main() {
    // 创建一个具有初始值的切片
    original := []int{1, 2, 3, 4, 5}

    // 创建一个子切片——两个切片共享相同的底层数组!
    subslice := original[1:3]

    fmt.Println("未修改的子切片:", subslice)  // 输出 => 未修改的子切片: [2 3]

    // 修改子切片
    subslice[0] = 42

    fmt.Println("原始切片:", original) // 输出 => 原始切片: [1 42 3 4 5]
    fmt.Println("修改后的子切片:", subslice)  // 输出 => 修改后的子切片: [42 3]
}
Copier après la connexion
Copier après la connexion
du nouveau sous-lisière est déterminée par la capacité restante de la tranche d'origine de la sous-section. Décomposons un peu:

Lorsque vous créez des tranches à partir de tableaux, la longueur de la tranche est le nombre d'éléments qu'il contenait à l'origine, et sa capacité est le nombre total d'éléments qu'il peut contenir avant de croître.

Obtenir un sous-actif

Lorsque vous obtenez la sous-lisière des tranches existantes:

  • La longueur est le nombre d'éléments que vous avez spécifiés.
  • <量> CAPACITÉ a calculé la capacité de la tranche d'origine moins l'indice de départ des sous-licences.
Voyons un exemple détaillé:

type slice struct {
    array unsafe.Pointer // 指向底层数组的指针
    len   int           // 切片中的元素数量
    cap   int           // 底层数组的容量
}
Copier après la connexion
Copier après la connexion
Copier après la connexion
    La tranche d'origine a 5 éléments et la longueur et la capacité sont 5.
  • Lorsque vous utilisez <时>, il pointe vers les éléments de l'indice 1 à 3 (2, 3, 4).
  • subslice := original[1:4] <<> La longueur
  • est 4-1 = 3. subslice <<> La capacité
  • est 5-1 = 4, car elle commence à partir de l'indice 1 et comprend des éléments à la fin de la tranche d'origine.
  • subslice <<> Trap!
  • <<>
C'est là que les développeurs sont souvent piégés. La fonction <函> dans le langage Go peut provoquer des comportements inattendus lors du traitement des sous-sections.

Partage de capacité inutilisé append() La capacité

de la sous-affection comprend des éléments qui n'appartiennent pas à leur longueur mais situés dans la gamme de capacité de tranchage d'origine. Cela signifie que si les sous-licences augmentent, il peut accéder ou modifier ces éléments. append()

considérons cet exemple:

<初> pointant initialement vers 2, 3, la capacité est de 4 (elle peut atteindre la fin de la tranche d'origine).

Lorsque vous ajoutez 60, 70 à <追>, il utilise la capacité excédentaire de la tranche d'origine.

<<> et
package main

import "fmt"

func main() {
    // 创建一个具有初始值的切片
    original := []int{1, 2, 3, 4, 5}

    // 创建一个子切片——两个切片共享相同的底层数组!
    subslice := original[1:3]

    fmt.Println("未修改的子切片:", subslice)  // 输出 => 未修改的子切片: [2 3]

    // 修改子切片
    subslice[0] = 42

    fmt.Println("原始切片:", original) // 输出 => 原始切片: [1 42 3 4 5]
    fmt.Println("修改后的子切片:", subslice)  // 输出 => 修改后的子切片: [42 3]
}
Copier après la connexion
Copier après la connexion
Les deux reflètent ces changements car ils partagent le même tableau sous-jacent.
  • subslice Êtes-vous surpris?
  • L'opération a modifié la tranche d'origine car il y a suffisamment de capacité dans le tableau sous-jacent. Cependant, si nous dépassons la portée de la capacité ou des éléments supplémentaires dépassant le permis de capacité, GO allouera un nouveau tableau pour les sous-sections pour briser le partage avec le tranchage d'origine:
  • subslice
  • Dans ce cas,
  • a créé un nouveau tableau sous-jacent car la capacité d'origine a dépassé. original subslice <免> La meilleure pratique pour éviter les pièges

append() <确> Clarifier la capacité

func main() {
    // 原始切片
    original := []int{1, 2, 3, 4, 5}

    // 创建一个子切片
    subslice := original[1:4] // 指向元素 2, 3, 4

    fmt.Println("子切片:", subslice)    // 输出 => 子切片: [2 3 4]
    fmt.Println("子切片的长度:", len(subslice)) // 输出 => 子切片的长度: 3
    fmt.Println("子切片的容量:", cap(subslice)) // 输出 => 子切片的容量: 4
}
Copier après la connexion

append()

Le principal avantage est:

i. Ceci est important - ce n'est pas seulement un nouveau chef de section, mais un tout nouveau tableau dans la mémoire.

ii. C'est comme une copie d'un fichier au lieu de partager le fichier d'origine.
  • <完> Utilisez l'expression complète de la tranche
func main() {
    original := []int{1, 2, 3, 4, 5}
    subslice := original[1:3] // 指向元素 2, 3

    fmt.Println("追加前原始切片:", original) // 输出 => [1 2 3 4 5]
    fmt.Println("追加前子切片:", subslice)       // 输出 => [2 3]
    fmt.Println("子切片的容量:", cap(subslice))    // 输出 => 4

    // 在容量范围内追加到子切片
    subslice = append(subslice, 60, 70)

    // 追加到子切片后打印
    fmt.Println("追加后原始切片:", original)  // 输出 => [1 2 3 60 70]
    fmt.Println("追加后子切片:", subslice)        // 输出 => [2 3 60 70]
}
Copier après la connexion

<将> Lorsque vous passez la tranche à une fonction qui ne devrait pas modifier les données d'origine, considérez la non-variabilité

make([]int, len(subslice))

copy() Le principal avantage est:

    i.
  • ii.

    III.

    <住> Rappelez-vous:

    La tranche est une référence au tableau sous-jacent
    • Sous-circuit et partage de la mémoire de partage parental
    • <创> si la création d'un nouveau tableau sous-jacent dépend de la capacité
    • Lors de l'ajout d'éléments d'éléments de sous-affectation avec capacité, il modifiera les données du tranchage parent. append()
    • Lorsque vous souhaitez éviter le partage, veuillez utiliser une gestion explicite de la mémoire
    • Lors du traitement des sous-licences, veuillez effectuer l'une des opérations suivantes:
    • Je vous souhaite un code heureux. N'oubliez pas que plus la capacité est grande, plus la responsabilité est grande, surtout dans le partage de la mémoire! ?
    type slice struct {
        array unsafe.Pointer // 指向底层数组的指针
        len   int           // 切片中的元素数量
        cap   int           // 底层数组的容量
    }
    Copier après la connexion
    Copier après la connexion
    Copier après la connexion

    Félicitations pour avoir lu cet article.


    Pensez-vous que cette ressource est utile? Avez-vous des questions? Ou avez-vous trouvé une erreur ou une faute de frappe? Veuillez laisser vos commentaires dans les commentaires.

    N'oubliez pas de partager cette ressource avec d'autres personnes qui peuvent en bénéficier. Suivez-moi pour obtenir plus d'informations.

    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 de ce site Web
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
Derniers articles par auteur
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal