La longitud de la longitud y el límite de capacidad de Go Slice Slice

0x00 Introducción
Ir Language Tour Ejemplo Longitud y capacidad del segmento

Las rebanadas tienen longitud y capacidad.
La longitud de un segmento es el número de elementos que contiene.
La capacidad de un segmento es el número desde su primer elemento hasta el final de sus elementos de matriz subyacentes.
La longitud y la capacidad de una rebanada s se pueden obtener mediante las expresiones len(s) y cap(s).

paquete principal

importar "fmt"

func main() {     s := []int{2, 3, 5, 7, 11, 13}     printSlice(s)

    // Interceptar el segmento para que su longitud sea 0
    s = s[:0]
    printSlice(s)

    // extender su longitud
    s = s[:4]
    printSlice(s)

    // Descartar los dos primeros valores
    s = s[2:]
    printSlice(s)
}

func printSlice(s []int) {     fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s) } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 longitud=6 tapa=6 [2 3 5 7 11 13] longitud=0 tapa=6 [] longitud = 4 tapa =6 [2 3 5 7] longitud =2 cap=4 [5 7] 1 2 3 4 0x01 El programa ejecuta 1, la primera salida es [2,3,5,7,11,13], la longitud es 6 y la capacidad es 6;



































2. Los punteros izquierdo y derecho apuntan a s[0] al mismo tiempo, por lo que la longitud es 0 y la capacidad es 6;

3. El puntero izquierdo apunta a s[0] y el puntero derecho apunta a s[4] Dado que el concepto de división solo incluye elementos a la izquierda y no elementos a la derecha, la longitud es 4, pero el puntero izquierdo está en s[0] y ha pasado por 0 elementos, por lo que la capacidad sigue siendo 6;

4. Sobre la base del corte en el paso 3, el puntero izquierdo apunta a s[2] y el puntero derecho apunta al extremo derecho, por lo que la longitud es 2. Dado que el puntero izquierdo ha pasado a través de dos elementos, todavía hay 4 elementos a la izquierda desde el extremo derecho, por lo que la capacidad es 4.


Lo más difícil de entender en este artículo es la capacidad de la rebanada.Podemos considerar la capacidad como la longitud total menos el valor del elemento que ha pasado el puntero izquierdo, por ejemplo: s[:0] ——> cap =
6 - 0 =6;
s[ 2:] ——> tapa = 6 - 2 = 4.

0x02 Dentro del segmento
Un segmento es una descripción de un segmento de matriz. Contiene un puntero a la matriz, la longitud del segmento y la capacidad (la longitud máxima del segmento).
[Falló la transferencia de la imagen del enlace externo, el sitio de origen puede tener un mecanismo anti-leeching, se recomienda guardar la imagen y cargarla directamente (img-Yci8EQBR-1585976257296)(https://blog.go-zh.org/go -slices-usage-and -internals_slice-struct.png)]
La estructura de la variable de segmento creada por make([]byte, 5) es la siguiente:
[Falló la transferencia de imagen del enlace externo, el sitio de origen puede tener un anti- mecanismo de leeching, se recomienda guardar la imagen y subirla directamente (img-kR7U0t8j-1585976257297)(https://blog.go-zh.org/go-slices-usage-and-internals_slice-1.png)]
El longitud es el número de elementos a los que hace referencia el segmento. La capacidad es el número de elementos de la matriz subyacente (comenzando en el puntero del segmento). La longitud, la capacidad y el área se explicarán en el siguiente ejemplo.
Avancemos y dividamos s, observando la estructura de datos del segmento y la matriz subyacente a la que hace referencia:

s = s[2:4]
1
[Error al guardar la imagen del enlace externo, el sitio de origen puede tener un mecanismo anti-leeching, se recomienda guardar la imagen y subirla directamente (img-tZTU83Aa-1585976257299)(https: //blog.go-zh.org/go-slices-usage-and-internals_slice-2.png)]
Las operaciones de división no copian el elemento al que apunta la división. Crea un nuevo segmento y reutiliza la matriz subyacente del segmento original. Esto hace que las operaciones de corte sean tan eficientes como la indexación de matrices. Por lo tanto, la modificación de elementos a través de un nuevo sector afectará a los elementos correspondientes del sector original.

d := []byte{'r', 'o', 'a', 'd'}
e := d[2:]
// e == []byte{'a', 'd'}
e[ 1] = 'm'
// e == []byte{'a', 'm'}
// d == []byte{'r', 'o', 'a', 'm'}
1
2
3
4
5
6
La longitud de la rebanada s creada anteriormente es menor que su capacidad. Podemos hacer crecer la longitud de la rebanada hasta su capacidad:

s = s[:cap(s)]
1
[Falló la transferencia de la imagen del enlace externo, el sitio de origen puede tener un mecanismo anti-leeching, se recomienda guardar la imagen y subirla directamente (img-t0aIOp7h-1585976257306)(https: //blog.go-en.org/go-slices-usage-and-internals_slice-3.png)]
los segmentos no pueden crecer más allá de su capacidad. Crecer más allá de la capacidad del segmento provocará una excepción de tiempo de ejecución, al igual que un índice fuera de los límites de un segmento o matriz provocaría una excepción. Asimismo, un índice menor que cero no se puede utilizar para acceder a los elementos que preceden a la porción.

0x03 Interceptar agregar
paquete principal

importar "fmt"

func main() {     s := []int{2, 3, 5, 7, 11, 13}     printSlice(s)

    // Interceptar el segmento para que su longitud sea 0
    s = s[:0]
    printSlice(s)

    // extiende su longitud
    s = s[:5]
    printSlice(s)
    
    // agrega s por primera vez
    = append(s, 1)
    printSlice(s)
    
    // agrega
    s por segunda vez = append(s, 1)
    imprimirRebanada(s)
}

func printSlice(s []int) {     fmt.Printf("len=%d cap=%d ptr=%p %v\n", len(s), cap(s), s, s) }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
len=6 cap=6 ptr=0x450000 [2 3 5 7 11 13]
len=0 cap =6 ptr=0x450000 []
len=5 cap=6 ptr=0x450000 [2 3 5 7 11]
len=6 cap=6 ptr=0x450000 [2 3 5 7 11 1]
len=7 cap=12 ptr=0x44e030 [ 2 3 5 7 11 1 1]
1
2
3
4
5
Al agregar por primera vez, la longitud no excede la capacidad, por lo que la capacidad no cambia.
Al agregar por segunda vez, la longitud excede la capacidad y la capacidad se duplicará en este momento.
Al mismo tiempo, la dirección de segmento agregada es diferente de la original, es decir:
la operación de agregar puede causar que dos variables de segmento que originalmente usaban la misma matriz subyacente usen matrices subyacentes diferentes.

0x04 Interceptar agregar
paquete principal

importar "fmt"

func main() {     s := []int{2, 3, 5, 7, 11, 13}     printSlice(s)

    // Interceptar el segmento para que su longitud sea 0
    s = s[:0]
    printSlice(s)

    // extiende su longitud
    s = s[:4]
    printSlice(s)
    
    // rebanada después de agregar
    s = append(s, 4)
    s = s[:6]
    printSlice(s)
}

func printSlice(s []int) {     fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s) } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 longitud = 6 tapa=6 [2 3 5 7 11 13] longitud=0 tapa=6 [] longitud= 4 tapa=6 [2 3 5 7] len=6 cap=6 [2 3 5 7 4 13] 1 2 3 4 Verifique un problema aquí. Después de agregar un 4 sobre la base de [2 3 5 7], obtenga la porción a plena capacidad y descubra que los últimos 13 todavía está allí Es solo que 11 se reemplaza por 4. Esto muestra que la escritura de append es sobrescribir los datos detrás del segmento uno por uno.




































La copia de segmento 0x05
se usa para copiar el contenido de un segmento de matriz a otro segmento de matriz. Si las dos porciones de matriz añadidas no tienen el mismo tamaño, se copiarán de acuerdo con la cantidad de elementos de la porción de matriz más pequeña.

paquete principal

importar "fmt"

func main() {     rebanada1 := []int{1, 2, 3, 4, 5}     rebanada2 := []int{5, 4, 3}     rebanada3 := []int{5, 4, 3}


    copy(slice2, slice1) // solo copiará los primeros 3 elementos de slice1 a slice2
    printSlice(slice2)
    
    copy(slice1, slice3) // solo copiará los 3 elementos de slice3 a las primeras 3 posiciones de slice1
    printSlice(slice1 )
}

func printSlice(s []int) {     fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s) } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 len=3 cap=3 [1 2 3] len =5 cap=5 [5 4 3 4 5] 1 2 Para aumentar la capacidad de una rebanada, debe crear una nueva, más grande segmento de capacidad y, a continuación, copie el contenido del segmento original en el segmento nuevo. Toda la técnica es una implementación común de lenguajes que admiten matrices dinámicas. El siguiente ejemplo duplica la capacidad del segmento s, primero crea un nuevo segmento t con el doble de capacidad, copia los elementos de s a t y luego asigna t a s:

























t := make([]byte, len(s), (cap(s)+1)*2) // +1 en caso de que cap(s) == 0 for i := range s { t[ i
]         = s[i] } s = t 1 2 3 4 5 La operación de copiar en el ciclo puede ser reemplazada por la función integrada de copiar. La función de copia copia los elementos del segmento de origen en el segmento de destino. Devuelve el número de elementos copiados.








func copy(dst, src []T) int
1
La función de copia admite la copia entre segmentos de diferentes longitudes (solo copia elementos de longitud del segmento más corto). Además, la función de copia maneja correctamente los casos en los que los segmentos de origen y destino se superponen.

Usando la función de copia, podemos simplificar el fragmento de código anterior:

t := make([]byte, len(s), (cap(s)+1)*2)
copy(t, s)
s = t
1
2
3
Una operación común es agregar datos al final del segmento . La siguiente función agrega elementos al final del sector, aumenta la capacidad del sector si es necesario y devuelve el sector actualizado:

func AppendByte(segmento []byte, datos ...byte) []byte {     m := len(segmento)     n := m + len(datos)     if n > cap(segmento) { // si es necesario, reasignar         // asignar el doble de lo que se necesita, para el crecimiento futuro.         newSlice := make([]byte, (n+1)*2)         copy(newSlice, slice)         slice = newSlice     }     slice = slice[0:n]     copy(slice[m:n], data)     return slice } 1 2 3 4 5 6 7 8 9 10 11 12 13下面是 AppendByte 的一种用法:

























p := []byte{2, 3, 5}
p = AppendByte(p, 7, 11, 13)
// p == []byte{2, 3, 5, 7, 11, 13}
1
2
3
similar La función AppendByte es útil porque proporciona un control total sobre el crecimiento del sector. Según las características del programa, puede ser deseable asignar bloques más pequeños o más grandes, o asignar más de un tamaño determinado.

0x06 Resumen
La longitud y la capacidad de un segmento son diferentes. La longitud representa la distancia desde el puntero izquierdo hasta el puntero derecho, y la capacidad representa la distancia desde el puntero izquierdo hasta el final de la matriz subyacente.
El mecanismo de expansión del segmento, al agregar, si la longitud excede la capacidad después del aumento, la capacidad se duplicará y la matriz subyacente se transformará al mismo tiempo.
El mecanismo de adición de segmentos consiste en sobrescribir y escribir los datos detrás del segmento uno por uno.
El mecanismo de copia de segmentos copia los elementos del segmento de matriz más pequeño.
0x07 Consulte
el apéndice de Slice en Golang para explicar los detalles de
las matrices y los Slices de Golang, y las trampas de la función de agregar
Go guide_La longitud y la capacidad de los segmentos
Go slices: uso y esencia
——————————— ——————
Declaración de derechos de autor: este artículo es un artículo original del blogger CSDN "Shower Scarecrow", siguiendo el acuerdo de derechos de autor CC 4.0 BY-SA, adjunte el enlace de la fuente original y esta declaración para su reimpresión.
Enlace original: https://blog.csdn.net/u013474436/article/details/88770501

Supongo que te gusta

Origin blog.csdn.net/qq_32907195/article/details/114115353
Recomendado
Clasificación