2010-08-02 18 views
39

Vengo de un fondo de C++ y estoy acostumbrado a usar la clase std::vector para cosas como esta. supongamos que quiero una matriz dinámica de estos:Cómo implementar matrices de tamaño variable en Ir

type a struct { 
    b int 
    c string 
} 

¿Cuál es la forma estándar de hacer esto?

Un fragmento sería muy útil

+0

en profundidad de lectura: https://blog.golang.org/go-slices-usage-and-internals – user

Respuesta

42

Use la orden interna append()

Ejemplo:

type mytype struct { 
    a, b int 
} 

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

Consulte la spec para obtener más información sobre la anexión.

+0

Una cosa más cthom06, si lo haría: Estoy usando "para _, t = rango (msgs)" donde msgs es un vector. Entonces tengo que lanzar t a mi msg struct. ¿Puedo hacer esto todo dentro de la declaración for en 1 línea? –

+0

@ tm1rbrt No lo creo. Al menos no con rango. – cthom06

+2

Tenga en cuenta que el paquete contenedor/vector ya no está. Ha sido suplantado por rebanadas de vainilla y la función de agregar. Las divisiones son, esencialmente, matrices de tamaño variable. –

1

es posible que también pueda conformarse con una porción. que es una matriz que conoce su longitud actual. Y puede tener una longitud de corriente separada y capacidad máxima. Tenga en cuenta que los valores aprobados para el tamaño inicial y la capacidad no tienen que ser constantes, por lo que puede crear una función que genere y devuelva segmentos de diferentes longitudes según sus parámetros.

El lado positivo es que un sector [] Int solo se puede indexar como una matriz, y devolverá las entradas cuando se utiliza de esta manera.

El inconveniente es que no crecerá automáticamente en la capacidad declarada. Effective Go tiene un ejemplo de cómo manejaría la reasignación.

el código sería

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 Slice contiene tres elementos: datos, la longitud, y la capacidad.

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

La variable s es una rebanada de enteros con una longitud de 0 y una capacidad de 10. El incorporada len() y la tapa() funciones le permiten obtener la longitud y la capacidad de una rebanada:

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

para aumentar la longitud de un segmento, simplemente re-slice:

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

Para disminuir la longitud, se puede tomar una sub-división:

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

Hay algunas formas más cortas para invocar a make():

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

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

Eso es todo muy bien, pero lo que si es necesario aumentar la longitud de un segmento más allá de su capacidad? Para hacer eso, necesita asignar un nuevo corte y copiar el contenido del antiguo corte al nuevo. (La función de "copia" es otra incorporado.)

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

El Effective Go document toma este ejemplo un poco más lejos, la implementación de una función Anexar que anexa una rebanada a otra, cambiar su tamaño si es necesario.

Las divisiones están respaldadas por matrices; Cuando haces() un sector de una capacidad específica, se asigna una matriz de esa capacidad en el fondo. La porción se convierte efectivamente en un "puntero inteligente" para esa matriz. Si pasa esa porción (o una subslice de esa porción) a otra función, se pasa como un puntero a esa misma matriz. Esto hace que las subcategorías sean muy baratas de crear; la asignación de la matriz de respaldo es costosa.

La biblioteca estándar de Go incluye una serie de paquetes de contenedor (por ejemplo, vector) que eliminan la necesidad de administrar manualmente las divisiones. Usa rodajas para mayor velocidad y clases de contenedores más elaboradas para mayor comodidad. (Diciendo eso, todavía utilizo rebanadas para la mayoría de las cosas).

Quizás se esté preguntando por qué tiene que pasar por todos estos problemas. Después de todo, muchos lenguajes proporcionan matrices de tamaño dinámico como primitivas. La razón de esto está ligada a la filosofía de Go. Los diseñadores de idiomas no se atreven a saber cuál es la política de asignación adecuada para su programa; en cambio, te dan las herramientas que necesitas para construir tus propias estructuras de datos.

+0

Si recrea la porción cada vez que la rebanada crece, consumirá mucho tiempo. Sin embargo, si duplica la capacidad de corte cada vez que crece más allá de su capacidad, probablemente no requiera tanto tiempo para insertar nuevos elementos en el sector. 't: = make ([] int, 5, 10) u: = make ([] int, 10, 20) etc ...' – Xeoncross

+0

@Xeoncros, el ['append'] (https://golang.org/pkg/builtin/# append) built-in ya es bastante inteligente acerca de la asignación de espacio extra; solo úsalo. –

+0

tenga en cuenta que esta parte es obsoleta: "aumentar la longitud de una porción más allá de su capacidad" ... "necesita asignar una nueva división y copiar el contenido de la división antigua a la nueva". ahora el 'append()' hace la reasignación. ver respuestas por cthom06 y Jessta. – minghua

14

La forma idiomática de hacer esto ha cambiado. La adición de las órdenes de agregar una función de() la función significa que se puede extender una rebanada de este modo:

type a struct { 
    b int 
    c string 
} 

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

Añadir() añadirá el artículo dado a la división si hay espacio o extender el corte si es no lo suficientemente grande

Más información sobre append() está aquí http://golang.org/doc/go_spec.html#Appending_and_copying_slices

Cuestiones relacionadas