Maison >développement back-end >Golang >Lire le code source sous-jacent de Golang Slice

Lire le code source sous-jacent de Golang Slice

藏色散人
藏色散人avant
2021-03-03 15:51:362961parcourir

Ce qui suit est une introduction au code source sous-jacent de Golang Slice (Slice) de la colonne du didacticiel go langage . J'espère que cela sera utile aux amis dans le besoin. !

Lire le code source sous-jacent de Golang Slice

Array

Avant de parler de découpage, parlons du tableau. Deux caractéristiques des tableaux

  • Une adresse mémoire continue, chaque élément est continu
  • Les éléments sont du même type, et le nombre d'éléments est fixe
Go sont des types de valeur, et les opérations de passage de paramètres d'affectation et de fonction copieront l'intégralité des données du tableau.

arr := [2]int{1,2}arr2 := arr
fmt.Printf("%p %p",&arr ,&arr2)//切片slice1 := []int{1,2}slice2 := slice1
fmt.Printf("%p %p",slice1 ,slice2)

Slice

Une tranche est une référence à un fragment continu d'un tableau, donc une tranche est un type de référence. Une tranche est un tableau de longueur variable.

La structure des données de Slice est définie comme suit :

runtime/slice.go#L13

type slice struct {
    array unsafe.Pointer    len   int
    cap   int}
    array est l'adresse du tableau sous-jacent
  • longueur de la tranche
  • capacité maximale de la tranche

Créer une tranche

src/runtime/slice.go#L83

func makeslice(et *_type, len, cap int) unsafe.Pointer {
    mem, overflow := math.MulUintptr(et.size, uintptr(cap))
    ....
    return mallocgc(mem, et, true)}
La logique de base est de demander un morceau de mémoire en fonction de la capacité.

Extension de tranche

L'expansion se produit lorsque la longueur de la tranche est supérieure à la capacité et que le tableau sous-jacent ne peut pas y tenir

func growslice(et *_type, old slice, cap int) slice {
    ...
    // 如果新要扩容的容量比原来的容量还要小,直接报panic
    if cap 6fcbe6a181235a2d91480a84b8bdbb32 doublecap {
        newcap = cap
    } else {
    // 旧容量 小于1024,新容量= 旧容量 * 2 也就是扩容1倍
        if old.cap c9221202ba118f4c45c4e2fcde42ff0d 0 && writeBarrier.enabled {
            bulkBarrierPreWriteSrcOnly(uintptr(p), uintptr(old.array), lenmem-et.size+et.ptrdata)
        }
    }
    //移动到p
    memmove(p, old.array, lenmem)
    //返回slice结构,让slice.array指向p
    return slice{p, old.len, newcap}}
    Nouveau plafond de capacité d'application, s'il est supérieur à 2 fois l'ancienne capacité (oldcap), la capacité à étendre (newcap) = le plafond de capacité nouvellement appliqué
  • Si l'ancienne capacité (oldcap) Si la valeur déborde, la capacité à étendre = la capacité nouvellement appliquée
  •   arr := make([]int,1024)
      arr = append(arr,1)
      fmt.Println(len(arr),cap(arr))// 1025,1280
      arr1 := make([]int,10)
      arr1 = append(arr1,1)
      fmt.Println(len(arr1),cap(arr1))//11 20
    Remarques : partage de tranches Le tableau sous-jacent, donc lorsque la tranche est attribuée, la modification de la tranche entraînera une modification du tableau sous-jacent, ce qui entraînera un BUG
  • arr := []int{1,2,3,4}
    arr1 := arr[:2] //[1,2]
    arr1 = append(arr1,5)
    fmt.Println(arr[3]) //5 修改了底层数组
    //例子2
    arr3 := []int{1,2,3,4}
    arr4 := arr3[2:]
    arr4 = append(arr4,10)//扩容 不会影响arr3
    fmt.Println(arr3)
Copie de tranche

src/runtime/slice.go#L247

//toPtr 目标地址 toLen目标长度
// width 元素大小
func slicecopy(toPtr unsafe.Pointer, toLen int, fromPtr unsafe.Pointer, fromLen int, width uintptr) int {
    //判断长度
    if fromLen == 0 || toLen == 0 {
        return 0
    }
    n := fromLen
    if toLen < n {
        n = toLen
    }
    //切片大小等于0
    if width == 0 {
        return n
    }

    size := uintptr(n) * width
    //特殊处理 如果只有一个元素并且大小是1byte,那么指针直接转换即可
    if size == 1 {
        *(*byte)(toPtr) = *(*byte)(fromPtr)
    } else {
        //从 fm.array 地址开始,拷贝到 to.array 地址之后
        memmove(toPtr, fromPtr, size)
    }
    return n
}


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:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer