2010-08-02 18 views
39

Pochodzę z tła w C++ i do takich rzeczy używam klasy std::vector. Załóżmy chcę dynamiczną tablicę z nich:W jaki sposób zaimplementować skalowalne macierze w Go

type a struct { 
    b int 
    c string 
} 

Jaki jest standardowy sposób to zrobić?

fragment byłby bardzo przydatny

+0

W pogłębionej lektury: https://blog.golang.org/go-slices-usage-and-internals – user

Odpowiedz

42

Użyj append() wbudowane

Przykład:

type mytype struct { 
    a, b int 
} 

func main() { 
    a := []mytype{mytype{1, 2}, mytype{3, 4}} 
    a = append(a, mytype{5, 6}) 
} 

odnoszą się do spec uzyskać więcej informacji na temat dopisywania.

+0

Jeszcze jedno cthom06, jeśli mogłoby to: Używam "dla _, t = zakresu (msgs)" gdzie msgs jest wektorem. Następnie muszę rzucić t do mojej struktury msg. Czy mogę to wszystko zrobić wewnątrz instrukcji for w 1 linii? –

+0

@ tm1rbrt Nie wierzę w to. Przynajmniej nie z zasięgiem. – cthom06

+2

Zwróć uwagę, że pakiet kontenera/wektor zniknął. Został wyparty przez plasterki wanilii i funkcję dopełniającą. Plasterki są zasadniczo skalowalnymi tablicami. –

1

możesz również być w stanie zrobić z plasterkiem. która jest tablicą, która zna jej aktualną długość. I może mieć oddzielną długość prądu i maksymalną pojemność. Zauważ, że wartości przekazane dla początkowego rozmiaru i pojemności nie muszą być stałe, więc możesz utworzyć funkcję, która buduje i zwraca wycinki o różnych długościach na podstawie jego parametrów.

Górą jest to, że plaster [] Int może być po prostu indeksowany jak tablica i zwróci int, gdy zostanie użyty w ten sposób.

Wadą jest to, że nie będzie automatycznie rosnąć o swoją określoną pojemność. Effective Go ma przykład tego, jak można poradzić sobie z realokacją.

kod byłby

type mytype struct { 
    a, b int 
} 




func main() { 

    sl := make([]mytype, 10, 50) //slice of 10 items, max capacity 50 these do not have to be constant expressions. 
    sl[0] = mytype{1,2} 
    //... 
    for i, value := range sl { 
    // ... do stuff with value 
    } 
} 
47

A Go plaster zawiera trzy elementy: dane, długość i pojemność.

s := make([]int, 0, 10) 

Zmienna s jest kawałek wskazówki o długości 0 i pojemności 10. Wbudowany len() i nasadki() funkcje pozwalają uzyskać długość i pojemność kawałek:

len(s) == 0 
cap(s) == 10 

Aby zwiększyć długość kawałek, po prostu re-slice:

s = s[0:5] 
// len(s) == 5 
// cap(s) == 10 

Aby zmniejszyć długość, można wziąć pod-plaster:

s = s[0:1] 
// len(s) == 1 

Istnieje kilka krótszych sposoby na wywołanie make():

a := make([]int, 10) 
// len(a) == cap(a) == 10 

b := make([]int) 
// len(b) == cap(b) == 0 

To wszystko dobrze, ale co jeśli trzeba zwiększyć długość wycinka poza jego zdolności? Aby to zrobić, musisz przydzielić nowy plasterek i skopiować zawartość starego plastra do nowego. (Funkcja „kopiuj” inny wbudowane.)

t := make([]int, len(s), 20) 
copy(t, s) 

Effective Go document trwa w tym przykładzie trochę dalej, realizując funkcję załącza dołącza jednego przedziału do drugiego rozmiaru, jeśli to konieczne.

Plasterki są poparte tablicami; po utworzeniu() wycinka o określonej pojemności tablica o tej pojemności jest przydzielana w tle. Wycinek efektywnie staje się "inteligentnym wskaźnikiem" dla tej tablicy. Jeśli przekażecie ten wycinek (lub podsystem tego wycinka) do innej funkcji, zostanie on przekazany jako wskaźnik do tej samej tablicy. To sprawia, że ​​subpiksele są bardzo tanie - tworzenie alokacji tablicy jest kosztowne.

Standardowa biblioteka Go zawiera wiele pakietów kontenerowych - na przykład wektor - które eliminują potrzebę ręcznego zarządzania plasterkami. Użyj plasterków dla szybkości i bardziej rozbudowanych klas kontenerów dla wygody. (Mówiąc to, nadal używam plasterków do większości rzeczy.)

Być może zastanawiasz się, dlaczego musisz iść na te wszystkie kłopoty. W końcu wiele języków udostępnia dynamicznie przeskalowane tablice jako prymitywy. Powód tego jest związany z filozofią Go. Projektanci języków nie zakładają, że wiedzą, jaka jest właściwa polityka alokacji dla twojego programu; zamiast tego oferują narzędzia potrzebne do tworzenia własnych struktur danych.

+0

Jeśli odtworzysz plasterek za każdym razem, gdy plasterek się powiększy, pochłonie to dużo czasu. Jeśli jednak podwoisz wydajność plasterka za każdym razem, gdy przekroczy on jego pojemność, prawdopodobnie nie będzie wymagać tak dużo czasu, aby wstawić nowe elementy do plasterka. 't: = make ([] int, 5, 10) u: = make ([] int, 10, 20) itp.' ' – Xeoncross

+0

@Xoncros, the [' append'] (https://golang.org/pkg/builtin/# append) wbudowane już jest dość inteligentne w przydzielaniu dodatkowej przestrzeni; po prostu go używaj. –

+0

należy pamiętać, że ta część jest już nieaktualna: "zwiększ długość plasterka poza jego pojemność" ... "musisz przydzielić nowy plaster i skopiować zawartość starego plasterka do nowego". teraz 'append()' dokonuje realokacji. zobacz odpowiedzi od cthom06 i Jessty. – minghua

14

Idiomatyczny sposób na zrobienie tego zmienił się. Dodanie wbudowanego append() funkcja oznacza, że ​​można rozszerzyć kawałek tak:

type a struct { 
    b int 
    c string 
} 

func main(){ 
    var mySlice []a 
    mySlice = append(mySlice,a{5,"pizza"}) 
} 

Append() dołączy dany element do plasterka jeśli jest pokój lub przedłużyć kawałek jeśli to nie jest wystarczająco duży.

Więcej informacji o append() jest tutaj http://golang.org/doc/go_spec.html#Appending_and_copying_slices

Powiązane problemy