arrays - una - tablas en matlab
¿Por qué usar matrices en lugar de rodajas? (4)
Como dijo Akavall, los arreglos son hashable. Eso significa que se pueden utilizar como una clave para un mapa.
También son pasadas por valor. Cada vez que lo pasa a una función, a una función o lo asigna a otra variable, hace una copia completa de la misma.
Pueden ser serializados por codificación / binario.
También se pueden utilizar para controlar el diseño de la memoria. Como no es una referencia, cuando se coloca en una estructura, asignará esa cantidad de memoria como parte de la estructura en lugar de colocar el equivalente de un puntero allí como lo haría una división.
En pocas palabras, no use una matriz a menos que sepa lo que está haciendo.
Hashable / serializable son agradables de tener, pero no estoy seguro de si son realmente tan convincentes de tener
¿Qué harías si quisieras tener un mapa de hash md5? No se puede usar un segmento de bytes, por lo que tendría que hacer algo como esto para sortear el sistema de tipos:
// 16 bytes
type hashableMd5 struct {a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p byte}
A continuación, cree una función de serialización para ello. Las matrices hashable significan que solo puede llamarlo un byte [16].
Suena como acercarse al centro comercial de C, tamaño de
No, eso no tiene nada que ver con malloc o sizeof. Esos son para asignar memoria y obtener el tamaño de una variable.
Sin embargo, CGo es otro caso de uso para esto. El comando cgo crea tipos que tienen el mismo diseño de memoria que sus tipos C correspondientes. Para hacer esto, a veces es necesario insertar matrices sin nombre para el relleno.
Si los problemas se pueden resolver con ... penalización de rendimiento nula / insignificante utilizando cortes ...
Las matrices también evitan que los indirectos hagan que ciertos tipos de código sean más rápidos. Por supuesto, esta es una optimización tan pequeña que es insignificante en casi todos los casos.
He estado leyendo sobre Go, y me quedé perplejo pensando en esta pregunta fundamental.
En Go, está bastante claro que los cortes son más flexibles y, por lo general, se pueden usar en lugar de arreglos cuando se necesita una secuencia de datos.
Al leer la mayor parte de la documentación, parece que están alentando a los desarrolladores a usar solo secciones en lugar de matrices. La impresión que me da la sensación de que los creadores podrían haber diseñado simplemente matrices para poder cambiarlas de tamaño y hacerlo sin la sección completa de sectores. De hecho, un diseño de este tipo hubiera hecho que el lenguaje fuera aún más fácil de entender, y quizás incluso haya fomentado un código más idiomático.
Entonces, ¿por qué los creadores permitieron matrices en primer lugar? ¿Cuándo se utilizarían matrices en lugar de rodajas? ¿Hay alguna vez una situación en la que el uso de matrices en segmentos sea convincente ?
Cuando consulté la documentación oficial ( http://golang.org/doc/effective_go.html#arrays ), la única parte útil que encontré fue:
Las matrices son útiles cuando se planifica el diseño detallado de la memoria y, a veces, pueden ayudar a evitar la asignación, pero principalmente son un componente básico para los segmentos.
Continuaron hablando sobre cómo las matrices son caras como valores y cómo simular el comportamiento de estilo C con el puntero. Incluso entonces, terminaron la sección del arreglo con una clara recomendación:
Pero incluso este estilo no es idiomático Go. Use rebanadas en su lugar.
Entonces, ¿cuáles son algunos ejemplos reales de "planificación del diseño detallado de la memoria" o "ayuda para evitar la asignación" para los cuales no serían adecuados los segmentos?
Para ampliar esto
Las matrices son útiles cuando se planifica el diseño detallado de la memoria y, a veces, pueden ayudar a evitar la asignación, pero principalmente son un componente básico para los segmentos.
Las matrices pueden ser más eficientes cuando se considera la sobrecarga de la asignación de almacenamiento dinámico. Piense en el recolector de basura, la gestión del montón y la fragmentación, etc.
Por ejemplo, si tiene una variable de matriz local como var x [8]int
que no se usa después de que la función regresa, lo más probable es que se asigne en la pila. Y la asignación de pila es mucho más barata que la asignación de pila.
También para estructuras anidadas como matrices de matrices o matrices dentro de estructuras, es más barato asignarlas en un blob en lugar de en varias piezas.
Por lo tanto, utilice matrices para secuencias relativamente cortas de tamaño fijo, por ejemplo, una dirección IP.
Para complementar la respuesta de Stephen Weinberg:
Entonces, ¿cuáles son algunos ejemplos reales de "planificación del diseño detallado de la memoria" o "ayuda para evitar la asignación" para los cuales no serían adecuados los segmentos?
Aquí hay un ejemplo para "planificar el diseño detallado de la memoria". Hay muchos formatos de archivo. Por lo general, un formato de archivo es así: comienza con un "número mágico" y luego sigue un encabezado informativo cuya estructura suele ser fija. Este encabezado contiene información sobre el contenido, por ejemplo, en el caso de un archivo de imagen, contiene información como el tamaño de la imagen (ancho, alto), el formato de píxeles, la compresión utilizada, el tamaño del encabezado, el desplazamiento de los datos de la imagen y similares (básicamente describe el resto del archivo). y como interpretarlo / procesarlo).
Si desea implementar un formato de archivo en Go, una forma fácil y conveniente es crear una struct
contenga los campos de encabezado del formato. Cuando quiera leer un archivo de tal formato, puede usar el método binary.Read()
para leer la struct
encabezado completa en una variable, y de manera similar, cuando desea escribir un archivo de ese formato, puede usar binary.Write()
para escribir el encabezado completo en un solo paso en el archivo (o donde sea que envíe los datos).
El encabezado puede contener incluso decenas o cien campos, aún puede leerlo / escribirlo con solo una llamada de método.
Ahora, como puede sentir, el "diseño de memoria" de la struct
encabezado debe coincidir exactamente con el diseño de bytes, ya que se guarda (o debe guardarse) en el archivo si desea hacerlo todo en un solo paso.
¿Y dónde entran las matrices en la imagen?
Muchos formatos de archivo suelen ser complejos porque quieren ser generales y, por lo tanto, permiten una amplia gama de usos y funcionalidades. Y muchas veces no desea implementar / manejar todo lo que el formato admite porque no le importa (porque solo desea extraer algo de información) o no tiene que hacerlo porque tiene garantías de que la entrada solo use un subconjunto o un formato fijo (de los muchos casos, el formato de archivo es totalmente compatible).
Entonces, ¿qué hace si tiene una especificación de encabezado con muchos campos pero solo necesita algunos de ellos? Puede definir una estructura que contendrá los campos que necesita, y entre los campos puede usar matrices con el tamaño de los campos que simplemente no le importa o no necesita. Esto asegurará que aún pueda leer todo el encabezado con una llamada de función, y las matrices serán básicamente el marcador de posición de los datos no utilizados en el archivo. También puede usar el identificador en blank como nombre de campo en la definición de la struct
del encabezado si no usa los datos.
Ejemplo teórico
Para un ejemplo sencillo, implementemos un formato en el que la magia sea "TGI" (Teórica Go Image) y el encabezado contenga campos como este: 2 palabras reservadas (16 bits cada una), 1 ancho de imagen de palabra, 1 altura de imagen de palabra, ahora viene 15 palabras clave "no importa", entonces la imagen ahorra tiempo como 8 bytes siendo nanosegundos desde el 1 de enero de 1970 UTC.
Esto se puede modelar con una estructura como esta (excluyendo el número mágico):
type TGIHeader struct {
_ uint16 // Reserved
_ uint16 // Reserved
Width uint32
Height uint32
_ [15]uint32 // 15 "don''t care" dwords
SaveTime int64
}
Para leer un archivo TGI e imprimir información útil:
func ShowInfo(name string) error {
f, err := os.Open(name)
if err != nil {
return err
}
defer f.Close()
magic := make([]byte, 3)
if _, err = f.Read(magic); err != nil {
return err
}
if !bytes.Equal(magic, []byte("TGI")) {
return errors.New("Not a TGI file")
}
th := TGIHeader{}
if err = binary.Read(f, binary.LittleEndian, &th); err != nil {
return err
}
fmt.Printf("%s is a TGI file,/n/timage size: %dx%d/n/tsaved at: %v",
name, th.Width, th.Height, time.Unix(0, th.SaveTime))
return nil
}
Una diferencia práctica es que los arrays
son hashable, mientras que los slices
no lo son.