Zadeklarować plasterek czy zrobić plasterek?

99

Jaka jest różnica między var s []inti s := make([]int, 0)?

Uważam, że oba działają, ale który z nich jest lepszy?

Wang Yi
źródło
Pierwsza tworzy nilplasterek, a druga emptyplasterek (taka jest terminologia używana w książce „Idź w akcji” ). Aby uniknąć publikowania tej samej odpowiedzi również tutaj, możesz sprawdzić stackoverflow.com/a/45997533/1561148
tgogos

Odpowiedzi:

95

Oprócz fabriziom „s odpowiedzi , można zobaczyć więcej przykładów na« Go: Wykorzystanie Plastry i internals », gdzie zastosowanie dla []intwspomina:

Ponieważ zerowa wartość wycinka ( nil) działa jak wycinek o zerowej długości , możesz zadeklarować zmienną wycinka, a następnie dołączyć do niej w pętli:

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

Oznacza to, że aby dołączyć do wycinka, nie musisz najpierw przydzielać pamięci: nilplasterek p int[]wystarczy jako plasterek do dodania.

VonC
źródło
Dlaczego myślisz, że przydzieliłoby to alokację? Cap wynosi zero, więc nic nie jest przydzielane z marką lub bez niej.
Arman Ordookhani
1
@ArmanOrdookhani Zgoda. Po prostu uważam, że deklaracja jest var p []intłatwiejsza niż używanie make(co kojarzy mi się bardziej z alokacją, mimo że z pułapem 0, to niczego by nie alokowało). Jeśli chodzi o czytelność, wolę nie używać maketutaj.
VonC
1
Jestem bardziej w kierunku używania dosłownych wszędzie (np p := []int{}.). Ponieważ zwykle używamy :=składni do deklarowania większości zmiennych, bardziej naturalne jest mieć ją wszędzie, zamiast mieć wyjątki dla wycinków. Poza tym myślenie o alokacjach zwykle skłania ludzi do przedwczesnej optymalizacji.
Arman Ordookhani
113

Prosta deklaracja

var s []int

nie przydziela pamięci i swskazuje na nil, while

s := make([]int, 0)

przydziela pamięć i swskazuje na pamięć wycinek z 0 elementami.

Zwykle pierwszy jest bardziej idiomatyczny, jeśli nie znasz dokładnego rozmiaru swojego przypadku użycia.

fabrizioM
źródło
Czy mogę powiedzieć to samo o mapie? var m map [string] int vs m: = make (map [string] int)? Dzięki.
joshua
11
Nie, potrzebujesz makemap, bo nawet puste mapmiejsce potrzebuje miejsca na jakąś księgowość.
twotwotwo
11
Jeśli chcesz zwrócić wycinek zawierający 0 elementów (zamiast „nil”), użyj make.
Jess
6
Jeśli budujesz interfejs API i zwracasz tablicę jako odpowiedź, użycie deklaratywnej formy zwróci nilw przypadku, gdy twój wycinek nie zawiera żadnego elementu, zamiast pustej tablicy. Jeśli jednak makezostanie użyty do utworzenia wycinka, zamiast tego zostanie zwrócona pusta tablica, co jest ogólnie pożądanym efektem.
robinmitra
6
Jak wspomniano w komentarzu do tej odpowiedzi: stackoverflow.com/a/29164565/1311538 , istnieją różnice podczas wykonywania takich czynności, jak kierowanie json. Marshaling the nil slice ( var s []int) wyprodukuje null, podczas gdy marshaling the empty slice ( s := make([]int, 0)) da oczekiwany[]
asgaines
8

Właśnie znalazłem różnicę. Jeśli użyjesz

var list []MyObjects

a następnie kodujesz dane wyjściowe jako JSON, otrzymujesz null.

list := make([]MyObjects, 0)

wyniki []zgodnie z oczekiwaniami.

Steve Hanov
źródło
tak, to drugie jest całkiem przydatne, gdy chcemy odpowiedzieć tablicą [] zamiast null
Nhan Tran
4

Nieco pełniej (jeszcze jeden argument make) przykład:

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

Na zewnątrz:

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

Lub z dynamicznym typem slice:

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

Na zewnątrz:

length:  2 - capacity 5 - content:  [<nil> <nil>]
Benyamin Jafari
źródło
2
Dobre przykłady. +1
VonC