Forma correcta de inicializar rebanada vacía


227

Para declarar un segmento vacío, con un tamaño no fijo, es mejor hacerlo:

mySlice1 := make([]int, 0)

o:

mySlice2 := []int{}

Solo me pregunto cuál es la forma correcta.


2
Dices "tamaño no fijo", pero los cortes nunca tienen un tamaño fijo. A menos que quiera decir con capacidad cero. Tenga en cuenta que si tiene una idea / conjetura / pista sobre la capacidad que podría necesitar, entonces usar la versión de tres argumentos es bueno. Por ejemplo, para construir una porción de teclas del mapa:keys := make([]int, 0, len(m)); for k, v := range m { keys := append(keys,k) }
Dave C

1
¿Posible duplicado de Declare slice o make slice?
usuario

Respuestas:


272

Las dos alternativas que proporcionó son semánticamente idénticas, pero el uso make([]int, 0)dará como resultado una llamada interna a runtime.makeslice (Ir 1.14).

También tiene la opción de dejarlo con un nilvalor:

var myslice []int

Como está escrito en el blog Golang.org :

un corte nulo es funcionalmente equivalente a un corte de longitud cero, aunque no apunta a nada. Tiene longitud cero y se puede agregar, con asignación.

Una nilrebanada será sin embargo json.Marshal()en "null"mientras que una rebanada vacía formar en "[]", como fuera puntiagudo por @farwayer.

Ninguna de las opciones anteriores causará ninguna asignación, como lo señaló @ArmanOrdookhani.


44
Mencione también en wiki github.com/golang/go/wiki/…
Grzegorz Żur

106
Tenga cuidado: json.Marshal()regresará nullpor var myslice []inty []para el segmento inicializadomyslice := []int{}
farwayer

10
También tenga cuidado: reflect.DeepEqualhace una distinción entre las rebanadas nil y rodajas no nulos: a := []int{}, var b []int,reflect.DeepEqual(a, b) // returns false
asgaines

1
¿Por qué crees que haría una asignación? El límite es cero, por lo que no se asigna nada. Todos los punteros a cosas de longitud cero apuntan a la misma ubicación en la memoria: play.golang.org/p/MPOKKl_sYvw
Arman Ordookhani

1
@ArmanOrdookhani Estás en lo correcto. Lo probé y también descubrí que estaba equivocado con mi suposición sobre instrucciones de montaje idénticas. ¡Fijo!
ANisus

65

Son equivalentes Ver este código:

mySlice1 := make([]int, 0)
mySlice2 := []int{}
fmt.Println("mySlice1", cap(mySlice1))
fmt.Println("mySlice2", cap(mySlice2))

Salida:

mySlice1 0
mySlice2 0

Ambas rebanadas tienen 0capacidad, lo que implica que ambas tienen 0longitud (no puede ser mayor que la capacidad), lo que implica que ambas rebanadas no tienen elementos. Esto significa que las 2 rebanadas son idénticas en todos los aspectos.

Ver preguntas similares:

¿Cuál es el punto de tener una rebanada nula y una rebanada vacía en golang?

nil slices vs non-nil slices vs empty slices in Go language


46

Como una adición a la respuesta de @ANisus ...

a continuación hay información del libro "Go in action" , que creo que vale la pena mencionar:

Diferencia entre nily emptyrebanadas

Si pensamos en una rebanada como esta:

[pointer] [length] [capacity]

luego:

nil slice:   [nil][0][0]
empty slice: [addr][0][0] // points to an address

rebanada nula

Son útiles cuando desea representar un segmento que no existe, como cuando ocurre una excepción en una función que devuelve un segmento.

// Create a nil slice of integers.
var slice []int

rebanada vacía

Los sectores vacíos son útiles cuando desea representar una colección vacía, como cuando una consulta de base de datos devuelve cero resultados.

// Use make to create an empty slice of integers.
slice := make([]int, 0)

// Use a slice literal to create an empty slice of integers.
slice := []int{}

Independientemente de si usted está utilizando una rebanada nula o una rodaja de vacío, la incorporada en funciones append, leny capfuncionan de la misma.


Vaya ejemplo de patio de recreo :

package main

import (
    "fmt"
)

func main() {

    var nil_slice []int
    var empty_slice = []int{}

    fmt.Println(nil_slice == nil, len(nil_slice), cap(nil_slice))
    fmt.Println(empty_slice == nil, len(empty_slice), cap(empty_slice))

}

huellas dactilares:

true 0 0
false 0 0

¿Podemos obtener la dirección del segmento vacío en un solo paso usando make?
Simin Jie

Si echamos un vistazo a la firma de la función , makeparece que no devuelve la dirección. Creo que no puedes hacerlo en un solo paso.
tgogos

13

La división vacía y la división nula se inicializan de manera diferente en Ir:

var nilSlice []int 
emptySlice1 := make([]int, 0)
emptySlice2 := []int{}

fmt.Println(nilSlice == nil)    // true
fmt.Println(emptySlice1 == nil) // false
fmt.Println(emptySlice2 == nil) // false

En cuanto a las tres rebanadas, len y cap son 0.


make([]int, 0)es lo mejor porque Jetbrains GoLand no se queja de que sea "innecesario" como lo hace en el caso de []int{}. Esto es útil para escribir pruebas unitarias.
Andrzej Rehmann
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.