Cómo asignar una cadena a una matriz de bytes

375

Quiero asignar una cadena a la matriz de bytes:

var arr [20]byte
str := "abc"
for k, v := range []byte(str) {
  arr[k] = byte(v)
}

¿Tienes otro método?

sofire
fuente
11
Si la longitud de stres mayor que la longitud de arr, obtendrá un error de "índice fuera de rango".
PeterSO el

Respuestas:

544

Seguro y simple:

[]byte("Here is a string....")
openwonk
fuente
14
Las mejores prácticas de codificación en Go son usar una porción de bytes []bytey no una matriz de bytes establecida [20]byteal convertir una cadena a bytes ... ¿No me crees? Echa un vistazo a la respuesta de Rob Pike en este hilo
openwonk
99
El OP preguntó sobre una matriz, no un segmento. En algunos casos, debe limitar el tamaño del segmento y utilizar una matriz en su lugar. Mi respuesta a continuación recorta los caracteres adicionales para asegurarse de que no desborde la matriz.
DavidG
3
Para aquellos que piensan que esto parece un poco extraño: esto es solo conversión de tipo en Go: golang.org/ref/spec#Conversions
Cnly
¿alguna forma de agregar múltiples cadenas y concatenarlas? por ejemplo []byte("one", "two")?
rakim
Desafortunadamente no, @rakim, solo puede pasar una cadena ... por lo tanto, primero debe concatenarlas o combinar varios segmentos de bytes (fuera del alcance de esta pregunta).
openwonk
149

Para la conversión de una cadena a una rebanada de bytes, string -> []byte:

[]byte(str)

Para convertir una matriz en un segmento [20]byte -> []byte:

arr[:]

Para copiar una cadena a una matriz string -> [20]byte:

copy(arr[:], str)

Igual que el anterior, pero primero convierte explícitamente la cadena en un segmento:

copy(arr[:], []byte(str))

  • La copyfunción incorporada solo copia en un segmento, desde un segmento.
  • Las matrices son "los datos subyacentes", mientras que los segmentos son "una ventana gráfica a los datos subyacentes".
  • El uso [:]hace que una matriz califique como un segmento.
  • Una cadena no califica como una rebanada que se puede copiar a , pero califica como una rebanada que se puede copiar a partir de (las cadenas son inmutables).
  • Si la cadena es demasiado larga, copysolo copiará la parte de la cadena que se ajuste.

Este código:

var arr [20]byte
copy(arr[:], "abc")
fmt.Printf("array: %v (%T)\n", arr, arr)

... da el siguiente resultado:

array: [97 98 99 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] ([20]uint8)

También lo hice disponible en Go Playground

Alejandro
fuente
Es posible que desee agregar un ejemplo para convertir un solo carácter. De esto deduje que b[i] = []byte("A")[0]funciona, pero b[i] = 'A'termina siendo mucho más limpio.
Alex Jansen
1
Eso no funciona para runas de varios bytes:b[1] = '本'
Alexander
110

Por ejemplo,

package main

import "fmt"

func main() {
    s := "abc"
    var a [20]byte
    copy(a[:], s)
    fmt.Println("s:", []byte(s), "a:", a)
}

Salida:

s: [97 98 99] a: [97 98 99 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
PeterSO
fuente
3
Esta es la única respuesta que realmente aborda la pregunta original.
Jack O'Connor
¿Por qué asignar 20 bytes en lugar de lo específico que realmente necesita para la cadena? Si la cadena necesita menos de 20, ¿no es un poco ineficiente? ¿Y también propenso a errores si supera los 20?
Sir
1
@Sir: No asignamos 20 bytes. Copiamos 3 bytes, la longitud de s, `La función de copia no es tonta. Agregar y copiar segmentos : "El número de elementos copiados es el mínimo de len (src) y len (dst)".
PeterSO
42

Pedazo de pastel:

arr := []byte("That's all folks!!")
Sameh Sharaf
fuente
8
Esto no parece estar respondiendo la pregunta. OP quería escribir los bytes de la cadena en una matriz existente que podría ser más larga que la cadena.
Jack O'Connor
2
[]byteSe prefiere el uso de rebanadas sobre las matrices [20]byte. La respuesta es correcta según las mejores prácticas; si las especificaciones o el código requieren matrices, utilícelas copyen su lugar (consulte los ejemplos en este hilo).
openwonk
25

Yo pienso que es mejor..

package main

import "fmt"

func main() {
    str := "abc"
    mySlice := []byte(str)
    fmt.Printf("%v -> '%s'",mySlice,mySlice )
}

Consulta aquí: http://play.golang.org/p/vpnAWHZZk7

chespinoza
fuente
3
No es mejor Está incorrecto. No hace lo que pedía la pregunta.
peterSO
10

Ir, convertir una cadena en un segmento de bytes

Necesita una forma rápida de convertir una cadena [] a un tipo de byte. Para usar en situaciones como el almacenamiento de datos de texto en un archivo de acceso aleatorio u otro tipo de manipulación de datos que requiera que los datos de entrada estén en tipo [] byte.

package main

func main() {

    var s string

    //...

    b := []byte(s)

    //...
}

que es útil cuando se usa ioutil.WriteFile, que acepta un segmento de bytes como parámetro de datos:

WriteFile func(filename string, data []byte, perm os.FileMode) error

Otro ejemplo

package main

import (
    "fmt"
    "strings"
)

func main() {

    stringSlice := []string{"hello", "world"}

    stringByte := strings.Join(stringSlice, " ")

    // Byte array value
    fmt.Println([]byte(stringByte))

    // Corresponding string value
    fmt.Println(string([]byte(stringByte)))
}

Salida:

[104 101 108 108 111 32 119 111 114 108 100] hola mundo

Por favor revise el enlace del patio de recreo

ASHWIN RAJEEV
fuente
0

Terminé creando métodos específicos de matriz para hacer esto. Al igual que el paquete de codificación / binario con métodos específicos para cada tipo int. Por ejemplo binary.BigEndian.PutUint16([]byte, uint16).

func byte16PutString(s string) [16]byte {
    var a [16]byte
    if len(s) > 16 {
        copy(a[:], s)
    } else {
        copy(a[16-len(s):], s)
    }
    return a
}

var b [16]byte
b = byte16PutString("abc")
fmt.Printf("%v\n", b)

Salida:

[0 0 0 0 0 0 0 0 0 0 0 0 0 97 98 99]

Observe cómo quería relleno a la izquierda, no a la derecha.

http://play.golang.org/p/7tNumnJaiN

DavidG
fuente
3
Si no está votando la respuesta, deje un comentario sobre por qué considera que la solución no es óptima o cómo no es relevante para la pregunta del OP.
DavidG
3
Creo que los votos negativos se deben a que byte16PutStringes una especie de reimplementación de la copyfunción incorporada , que solo admite la creación de nuevas matrices en lugar de utilizar una existente. copytiene un soporte especial para el compilador, por lo que puede manejar diferentes tipos de argumentos, y probablemente tenga una implementación de alto rendimiento bajo las cubiertas. Además, la pregunta del OP se refería a escribir una cadena en una matriz existente, en lugar de asignar una nueva, aunque la mayoría de las otras respuestas parecen ignorar eso también ...
Jack O'Connor
Gracias @ JackO'Connor También estoy aquí por el aprendizaje y aprecio los comentarios constructivos, no solo el simple voto negativo.
DavidG
No sé si su answer
voto negativo
-1

Además de los métodos mencionados anteriormente, también puedes hacer un truco como

s := "hello"
b := *(*[]byte)(unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&s))))

Ir a jugar: http://play.golang.org/p/xASsiSpQmC

Nunca deberías usar esto :-)

Brandon Gao
fuente
1
Esto es Loco. Creo que vale la pena agregar "pero no deberías" al final de tu respuesta. Aparte del hecho de que realmente no responde a la pregunta (OP habla de la matriz de bytes, no de las rebanadas), parece que no obtiene un []byteobjeto adecuado utilizando su "conversión"; falla gravemente cuando intenta modificar p, vea: play.golang.org/p/WHGl756ucj . En su caso, no estoy seguro de por qué preferiría doble inseguro sobre el b := []byte(s)método.
tomasz
1
@tomasz No prefiero hacer el string <-> [] byte de esta manera, solo mostrando una opción diferente :-) y sí, tienes razón, no entendí la pregunta.
Brandon Gao
Cuando hago esto, el resultado tiene un cap()tamaño arbitrario, lo que significa que está leyendo en memoria desconocida. Para que esto sea correcto, creo que debe asegurarse de asignar el reflect.SliceHeadertamaño completo y configurarlo manualmente cap. Algo como esto: play.golang.org/p/fBK4dZM-qD
Lye Fish
Y ni siquiera estoy seguro de eso .------------- ^ - Quizás esto es mejor: play.golang.org/p/NJUxb20FTG
Lye Fish
-1

Las matrices son valores ... las rebanadas son más como punteros. Eso [n]typeno es compatible, []typeya que son fundamentalmente dos cosas diferentes. Puede obtener un segmento que apunte a una matriz mediante el uso arr[:]que devuelve un segmento que tiene arrcomo respaldo de almacenamiento.

Una forma de convertir un trozo de, por ejemplo, []bytea [20]bytees asignar en realidad una [20]byteque se puede hacer mediante el uso var [20]byte(ya que es un valor ... no makees necesario) y luego copiar datos en él:

buf := make([]byte, 10)
var arr [10]byte
copy(arr[:], buf)

Esencialmente, lo que muchas otras respuestas se equivocan es que []typeNO es una matriz.

[n]Ty []Tson cosas completamente diferentes!

Cuando se utiliza el reflejo, []Tno es de tipo Array sino de tipo Slice y [n]Tes de tipo Array.

Tampoco puedes usar map[[]byte]Tpero puedes usarmap[[n]byte]T .

Esto a veces puede ser engorroso porque muchas funciones funcionan, por ejemplo, []bytemientras que algunas funciones regresan [n]byte(más notablemente las funciones hash en crypto/*). Un hash sha256, por ejemplo, es [32]bytey no es []byteasí cuando los principiantes intentan escribirlo en un archivo, por ejemplo:

sum := sha256.Sum256(data)
w.Write(sum)

obtendrán un error. La forma correcta de usar

w.Write(sum[:])

Sin embargo, ¿qué es lo que quieres? ¿Solo accediendo a la cadena bytewise? Puede convertir fácilmente un stringa []byteusando:

bytes := []byte(str)

pero esto no es una matriz, es un segmento. Además byte,! = rune. En caso de que desee operar con "personajes", debe usar rune... no byte.

mroman
fuente