reflect golang example go go-reflect

example - golang reflect



Convierte entre sectores de diferentes tipos (6)

Como han dicho otros, lanzar el puntero se considera mala forma en Go. Aquí hay ejemplos de la forma adecuada de Go y el equivalente de la transmisión de matriz C.

ADVERTENCIA: todo el código no probado.

La manera correcta

En este ejemplo, estamos utilizando el paquete de encoding/binary para convertir cada conjunto de 4 bytes en un int32 . Esto es mejor porque estamos especificando la endianidad. Tampoco estamos utilizando el paquete unsafe para romper el sistema de tipos.

import "encoding/binary" const SIZEOF_INT32 = 4 // bytes data := make([]int32, len(raw)/SIZEOF_INT32) for i := range data { // assuming little endian data[i] = int32(binary.LittleEndian.Uint32(raw[i*SIZEOF_INT32:(i+1)*SIZEOF_INT32])) }

The Wrong Way (Fundición de matriz C)

En este ejemplo, le estamos diciendo a Go que ignore el sistema de tipos. Esta no es una buena idea porque puede fallar en otra implementación de Go. Está asumiendo cosas que no están en la especificación del lenguaje. Sin embargo, este no hace una copia completa. Este código no es seguro para acceder al "SliceHeader", que es común en todos los sectores. El encabezado contiene un puntero a los datos (matriz C), la longitud y la capacidad. En lugar de simplemente convertir el encabezado al nuevo tipo de división, primero debemos cambiar la longitud y la capacidad, ya que hay menos elementos si tratamos los bytes como un tipo nuevo.

import ( "reflect" "unsafe" ) const SIZEOF_INT32 = 4 // bytes // Get the slice header header := *(*reflect.SliceHeader)(unsafe.Pointer(&raw)) // The length and capacity of the slice are different. header.Len /= SIZEOF_INT32 header.Cap /= SIZEOF_INT32 // Convert slice header to an []int32 data := *(*[]int32)(unsafe.Pointer(&header))

Obtengo un segmento de bytes ( []byte ) desde un socket UDP y quiero tratarlo como un segmento entero ( []int32 ) sin cambiar el conjunto subyacente, y viceversa. En C (++), simplemente lanzaría entre tipos de punteros; ¿Cómo haré esto en Go?


Hace lo que hace en C, con una excepción: Go no permite convertir de un tipo de puntero a otro. Bueno, lo hace, pero debe usar inseguro. Puntero para decirle al compilador que usted sabe que todas las reglas están rotas y usted sabe lo que está haciendo. Aquí hay un ejemplo:

package main import ( "fmt" "unsafe" ) func main() { b := []byte{1, 0, 0, 0, 2, 0, 0, 0} // step by step pb := &b[0] // to pointer to the first byte of b up := unsafe.Pointer(pb) // to *special* unsafe.Pointer, it can be converted to any pointer pi := (*[2]uint32)(up) // to pointer to the first uint32 of array of 2 uint32s i := (*pi)[:] // creates slice to our array of 2 uint32s (optional step) fmt.Printf("b=%v i=%v/n", b, i) // all in one go p := (*[2]uint32)(unsafe.Pointer(&b[0])) fmt.Printf("b=%v p=%v/n", b, p) }

Obviamente, debe tener cuidado con el uso del paquete "inseguro", ya que el compilador Go ya no está sosteniendo su mano, por ejemplo, podría escribir pi := (*[3]uint32)(up) aquí y el compilador no se quejaría, pero estarías en problemas

Además, como ya indicaron otras personas, los bytes de uint32 pueden tener un diseño diferente en diferentes computadoras, por lo que no debe suponer que estos son diseños como usted los necesita.

El enfoque más seguro sería leer su matriz de bytes uno por uno y hacer lo que necesite de ellos.

Alex


La respuesta corta es que no puedes. Ir no le permitirá lanzar una porción de un tipo a una porción de otro tipo. Tendrás un bucle en la matriz y crearás otra matriz del tipo que desees mientras lanzas cada elemento en la matriz. Esto generalmente se considera como algo bueno ya que la seguridad de tipo es una característica importante de go.


Puedes hacerlo con el paquete "inseguro"

package main import ( "fmt" "unsafe" ) func main() { var b [8]byte = [8]byte{1, 2, 3, 4, 5, 6, 7, 8} var s *[4]uint16 = (*[4]uint16)(unsafe.Pointer(&b)) var i *[2]uint32 = (*[2]uint32)(unsafe.Pointer(&b)) var l *uint64 = (*uint64)(unsafe.Pointer(&b)) fmt.Println(b) fmt.Printf("%04x, %04x, %04x, %04x/n", s[0], s[1], s[2], s[3]) fmt.Printf("%08x, %08x/n", i[0], i[1]) fmt.Printf("%016x/n", *l) } /* * example run: * $ go run /tmp/test.go * [1 2 3 4 5 6 7 8] * 0201, 0403, 0605, 0807 * 04030201, 08070605 * 0807060504030201 */


Tuve el problema de tamaño desconocido y modifiqué el método inseguro anterior con el siguiente código. dado un segmento de byte b ...

int32 slice is (*(*[]int)(Pointer(&b)))[:len(b)/4]

El ejemplo de matriz para cortar puede tener una gran constante ficticia y los límites de corte utilizados de la misma manera ya que no se asigna ninguna matriz.


http://play.golang.org/p/w1m5Cs-ecz

package main import ( "fmt" "strings" ) func main() { s := []interface{}{"foo", "bar", "baz"} b := make([]string, len(s)) for i, v := range s { b[i] = v.(string) } fmt.Println(strings.Join(b, ", ")) }