Richtiger Weg, um ein leeres Slice zu initialisieren

225

Um ein leeres Slice mit einer nicht festgelegten Größe zu deklarieren, ist es besser:

mySlice1 := make([]int, 0)

oder:

mySlice2 := []int{}

Ich frage mich nur, welcher der richtige Weg ist.

eouti
quelle
2
Sie sagen "nicht feste Größe", aber Slices haben niemals eine feste Größe. Es sei denn, Sie meinen mit null Kapazität. Hinweis: Wenn Sie eine Idee / Vermutung / einen Hinweis darauf haben, welche Kapazität Sie möglicherweise benötigen, ist die Verwendung der Version mit drei Argumenten gut. ZB um ein Stück Kartenschlüssel zu bauen:keys := make([]int, 0, len(m)); for k, v := range m { keys := append(keys,k) }
Dave C
1
Mögliches Duplikat von Slice deklarieren oder Slice erstellen?
Benutzer

Antworten:

270

Die beiden von Ihnen angegebenen Alternativen sind semantisch identisch. Die Verwendung make([]int, 0)führt jedoch zu einem internen Aufruf von runtime.makeslice (Go 1.14).

Sie haben auch die Möglichkeit, einen nilWert zu hinterlassen :

var myslice []int

Wie im Golang.org-Blog geschrieben :

Ein Null-Slice entspricht funktional einem Slice mit der Länge Null, obwohl es auf nichts zeigt. Es hat die Länge Null und kann mit Zuordnung angehängt werden.

Ein nilSlice wird jedoch json.Marshal()in, "null"während ein leeres Slice in "[]", wie von @farwayer hervorgehoben.

Keine der oben genannten Optionen führt zu einer Zuweisung, wie von @ArmanOrdookhani hervorgehoben.

ANisus
quelle
4
Erwähnen Sie auch auf wiki github.com/golang/go/wiki/…
Grzegorz Żur
105
Seien Sie json.Marshal()nullvar myslice []int[]myslice := []int{}
vorsichtig
10
Auch Vorsicht: reflect.DeepEqualmacht eine Unterscheidung zwischen null Scheiben und Nicht-Null - Scheiben: a := []int{}, var b []int,reflect.DeepEqual(a, b) // returns false
asgaines
1
Warum denkst du, würde es eine Allokation machen? Die Obergrenze ist Null, daher wird nichts zugewiesen. Alle Zeiger auf Dinge mit der Länge Null zeigen auf dieselbe Stelle im Speicher: play.golang.org/p/MPOKKl_sYvw
Arman Ordookhani
1
@ArmanOrdookhani Du bist richtig. Ich habe es ausprobiert und festgestellt, dass ich mit meiner Annahme einer identischen Montageanleitung falsch lag. Fest!
ANisus
64

Sie sind gleichwertig. Siehe diesen Code:

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

Ausgabe:

mySlice1 0
mySlice2 0

Beide Slices haben eine 0Kapazität, was bedeutet, dass beide Slices eine Kapazität haben0 Länge haben (kann nicht größer als die Kapazität sein), was bedeutet, dass beide Slices keine Elemente haben. Dies bedeutet, dass die 2 Scheiben in jeder Hinsicht identisch sind.

Siehe ähnliche Fragen:

Was bringt es, in Golang keine Scheibe und keine leere Scheibe zu haben?

Null-Scheiben gegen Nicht-Null-Scheiben gegen leere Scheiben in der Go-Sprache

icza
quelle
46

Als Ergänzung zu @ANisus ' Antwort ...

Im Folgenden finden Sie einige Informationen aus dem Buch "Go in Action" , die meiner Meinung nach erwähnenswert sind:

Unterschied zwischen nil& emptyScheiben

Wenn wir an eine Scheibe wie diese denken:

[pointer] [length] [capacity]

dann:

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

keine Scheibe

Sie sind nützlich, wenn Sie ein nicht vorhandenes Slice darstellen möchten, z. B. wenn in einer Funktion, die ein Slice zurückgibt, eine Ausnahme auftritt.

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

leere Scheibe

Leere Slices sind nützlich, wenn Sie eine leere Sammlung darstellen möchten, z. B. wenn eine Datenbankabfrage keine Ergebnisse zurückgibt.

// 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{}

Unabhängig davon , ob Sie eine Null Scheibe oder eine leere Scheibe verwendet, die integrierten Funktionen append, lenund capArbeit gleich.


Beispiel für einen Spielplatz :

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))

}

Drucke:

true 0 0
false 0 0
tgogos
quelle
Können wir die Adresse des leeren Slice in einem Schritt mit abrufen make?
Simin Jie
Wenn wir einen Blick auf die Funktion übernehmen Signatur , makescheint nicht die Adresse zurückzukehren. Ich glaube, Sie können es nicht in einem Schritt tun.
Tgogos
13

Leeres Slice und Null-Slice werden in Go unterschiedlich initialisiert:

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

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

Wie bei allen drei Scheiben sind len und cap 0.

Joe.CK
quelle
make([]int, 0)ist das Beste, weil Jetbrains GoLand sich nicht darüber beschwert, dass es "unnötig" ist, wie es im Fall von der Fall ist []int{}. Dies ist nützlich beim Schreiben von Komponententests.
Andrzej Rehmann