¿Declarar rebanada o hacer rebanada?

99

En Go, ¿cuál es la diferencia entre var s []inty s := make([]int, 0)?

Encuentro que ambos funcionan, pero ¿cuál es mejor?

Wang Yi
fuente
El primero crea un nilsegmento, mientras que el segundo crea un emptysegmento (esta es la terminología utilizada por el "Libro de acción" ). Para evitar publicar la misma respuesta aquí también, puede consultar stackoverflow.com/a/45997533/1561148
tgogos

Respuestas:

95

Además de la respuesta de fabriziom , puede ver más ejemplos en " Go Slices: uso e internos ", donde se menciona el uso de :[]int

Dado que el valor cero de un segmento ( nil) actúa como un segmento de longitud cero , puede declarar una variable de segmento y luego agregarla en un bucle:

// Filter returns a new slice holding only
// the elements of s that satisfy f()
func Filter(s []int, fn func(int) bool) []int {
    var p []int // == nil
    for _, v := range s {
        if fn(v) {
            p = append(p, v)
        }
    }
    return p
}

Significa que, para agregar a un segmento, no es necesario asignar memoria primero: el nilsegmento p int[]es suficiente como un segmento para agregar.

VonC
fuente
¿Por qué crees que haría una asignación? El límite es cero, por lo que no se asigna nada con o sin marca.
Arman Ordookhani
1
@ArmanOrdookhani De acuerdo. Simplemente encuentro la declaración var p []intmás fácil que usar make(que asocio más con la asignación, aunque con un límite de 0, no asignaría nada). En términos de legibilidad, prefiero no usar makeaquí.
VonC
1
Estoy más a favor de usar literales en todas partes (por ejemplo p := []int{}). Dado que usualmente usamos :=sintaxis para declarar la mayoría de las variables, es más natural tenerla en todas partes en lugar de tener excepciones para los segmentos. Aparte de esto, tratar de pensar en asignaciones generalmente empuja a las personas hacia optimizaciones prematuras.
Arman Ordookhani
113

Declaración simple

var s []int

no asigna memoria y sapunta a nil, mientras

s := make([]int, 0)

asigna memoria y sapunta a la memoria a un segmento con 0 elementos.

Por lo general, el primero es más idiomático si no conoce el tamaño exacto de su caso de uso.

fabrizioM
fuente
¿Puedo decir lo mismo del mapa? var m map [string] int vs m: = make (map [string] int)? Gracias.
Josué
11
No, necesitas makemapas, porque incluso un mapespacio vacío necesita espacio asignado para algo de contabilidad.
twotwotwo
11
Si necesita devolver un segmento con 0 elementos (en lugar de 'nil'), make es el uso correcto.
Jess
6
Si está creando una API y devuelve una matriz como respuesta, el uso de la forma declarativa se devolverá nilen caso de que su segmento no tenga ningún elemento, en lugar de una matriz vacía. Sin embargo, si makese usa para crear el segmento, se devolverá una matriz vacía en su lugar, que generalmente es el efecto deseado.
robinmitra
6
Como se menciona en un comentario sobre esta respuesta: stackoverflow.com/a/29164565/1311538 , existen diferencias al intentar hacer cosas como json marshaling. La clasificación del segmento nulo ( var s []int) producirá null, mientras que el cálculo del segmento vacío ( s := make([]int, 0)) producirá el esperado[]
asgaines
8

Solo encontré una diferencia. Si utiliza

var list []MyObjects

y luego codificas la salida como JSON, obtienes null.

list := make([]MyObjects, 0)

resultados []como se esperaba.

Steve Hanov
fuente
yah, este último es bastante útil cuando queremos responder con [] matriz en lugar de nulo
Nhan Tran
4

Un makeejemplo un poco más completo (un argumento más en ):

slice := make([]int, 2, 5)
fmt.Printf("length:  %d - capacity %d - content:  %d", len(slice), cap(slice), slice)

Fuera:

length:  2 - capacity 5 - content:  [0 0]

O con tipo dinámico de slice:

slice := make([]interface{}, 2, 5)
fmt.Printf("length:  %d - capacity %d - content:  %d", len(slice), cap(slice), slice)

Fuera:

length:  2 - capacity 5 - content:  [<nil> <nil>]
Benyamin Jafari
fuente
2
Buenos ejemplos. +1
VonC