Como atribuir string à matriz de bytes

375

Eu quero atribuir seqüência de caracteres à matriz de bytes:

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

Tem outro método?

sofire
fonte
11
Se o comprimento de strfor maior que o comprimento de arr, você receberá um erro "índice fora do intervalo".
PeterSO

Respostas:

543

Seguro e simples:

[]byte("Here is a string....")
openwonk
fonte
14
As melhores práticas de codificação no Go são usar uma fatia de bytes []bytee não uma matriz definida de bytes [20]byteao converter uma string em bytes ... Não acredita em mim? Confira a resposta de Rob Pike neste tópico
openwonk
9
O OP perguntou sobre uma matriz, não uma fatia. Em alguns casos, você precisa limitar o tamanho da fatia e usar uma matriz. Minha resposta abaixo apara os caracteres extras para garantir que você não exceda a matriz.
DavidG 14/02
3
Para aqueles que pensam que este parece um pouco estranho: esta é a conversão basta digitar Go: golang.org/ref/spec#Conversions
Cnly
alguma maneira de adicionar várias strings e concatená-las? por exemplo []byte("one", "two")?
rakim 07/02
Infelizmente não, @rakim, você só pode passar uma string ... então, você deve concatená-las primeiro ou combinar várias fatias de bytes (fora do escopo desta pergunta).
openwonk 9/02
149

Para converter de uma sequência de caracteres em uma fatia de bytes string -> []byte:

[]byte(str)

Para converter uma matriz em uma fatia [20]byte -> []byte:

arr[:]

Para copiar uma string para uma matriz string -> [20]byte:

copy(arr[:], str)

O mesmo que acima, mas convertendo explicitamente a string em uma fatia primeiro:

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

  • A copyfunção interna copia apenas para uma fatia, de uma fatia.
  • Matrizes são "os dados subjacentes", enquanto as fatias são "uma janela de visualização para dados subjacentes".
  • Usar [:]faz com que uma matriz seja qualificada como uma fatia.
  • Uma corda não se qualifica como uma fatia que pode ser copiado para , mas ela se qualifica como uma fatia que pode ser copiado a partir de (strings são imutáveis).
  • Se a sequência for muito longa, copycopia apenas a parte da sequência que se encaixa.

Este código:

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

... fornece a seguinte saída:

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

Também disponibilizei no Go Playground

Alexander
fonte
Você pode querer adicionar um exemplo para converter um único caractere. Deduzi disso que b[i] = []byte("A")[0]funciona, mas b[i] = 'A'acaba sendo muito mais limpo.
Alex Jansen
11
Isso não funciona para runas de vários bytes:b[1] = '本'
Alexander
110

Por exemplo,

package main

import "fmt"

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

Resultado:

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
fonte
3
Esta é a única resposta que realmente aborda a pergunta original.
Jack O'Connor
Por que atribuir 20 bytes em vez de específicos sobre o que você realmente precisa para a string? Se a string precisa de menos de 20, não é um pouco ineficiente? E também propenso a erros se exceder 20?
19417 Sir
11
@ Sir: Nós não atribuímos 20 bytes. Copiamos 3 bytes, o comprimento de s, A função de cópia `não é burra. Anexando e copiando fatias : "O número de elementos copiados é o mínimo de len (src) e len (dst)."
peterSO
42

Pedaco de bolo:

arr := []byte("That's all folks!!")
Sameh Sharaf
fonte
8
Isso não parece estar respondendo à pergunta. O OP queria gravar os bytes da string em uma matriz existente que poderia ser maior que a string.
Jack O'Connor
2
O uso de fatias []byteé preferível às matrizes [20]byte. A resposta está correta com base nas melhores práticas; se as especificações ou o código exigirem matrizes, use-o copy(consulte exemplos em outras partes deste encadeamento).
openwonk
25

Eu acho melhor..

package main

import "fmt"

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

Verifique aqui: http://play.golang.org/p/vpnAWHZZk7

chespinoza
fonte
3
Não é melhor Está errado. Não faz o que a pergunta pediu.
peterSO
10

Vá, converta uma string em uma fatia de bytes

Você precisa de uma maneira rápida de converter uma string [] para o tipo de byte []. Para usar em situações como armazenar dados de texto em um arquivo de acesso aleatório ou outro tipo de manipulação de dados que exija que os dados de entrada sejam do tipo [] byte.

package main

func main() {

    var s string

    //...

    b := []byte(s)

    //...
}

o que é útil ao usar o ioutil.WriteFile, que aceita uma fatia de bytes como parâmetro de dados:

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

Outro exemplo

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)))
}

Resultado:

[104 101 108 108 111 32 119 111 114 108 100] olá mundo

Por favor, verifique o link playground

ASHWIN RAJEEV
fonte
0

Acabou criando métodos específicos de matriz para fazer isso. Muito parecido com o pacote de codificação / binário com métodos específicos para cada tipo int. Por exemplo 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)

Resultado:

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

Observe como eu queria estofar à esquerda, não à direita.

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

DavidG
fonte
3
Se você está votando negativamente a resposta, deixe um comentário sobre por que você acha a solução não ideal ou como ela não é relevante para a pergunta do OP.
DavidG
3
Eu acho que os downvotes são porque byte16PutStringé uma espécie de reimplementação da copyfunção embutida, que apenas suporta a criação de novas matrizes em vez de usar uma existente. copypossui suporte especial ao compilador, para que ele possa lidar com diferentes tipos de argumentos e provavelmente possui uma implementação de alto desempenho oculta. Além disso, a pergunta do OP perguntou sobre a escrita de uma string para uma matriz existente, em vez de alocar um novo, embora a maioria das outras respostas parecem estar ignorando isso também ...
Jack O'Connor
Obrigado @ JackO'Connor Também estou aqui pelo aprendizado e aprecio o feedback construtivo, e não apenas o voto simples.
DavidG
não sei y seu baixo votou answerestá correto cada corpo está aqui para aprender e encorajar outros
Helius Muthukumar
-1

Além dos métodos mencionados acima, você também pode fazer um truque como

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

Go Play: http://play.golang.org/p/xASsiSpQmC

Você nunca deve usar isso :-)

Brandon Gao
fonte
11
Isso é loucura. Eu acho que vale a pena adicionar "mas você não deveria" ao final de sua resposta. Além do fato de ela realmente não responder à pergunta (o OP fala sobre matriz de bytes, não fatias), você não parece ter um []byteobjeto adequado usando sua "conversão" - falha muito quando tenta alterar p, consulte: play.golang.org/p/WHGl756ucj . No seu caso, não saiba por que você prefere o dobro do risco ao b := []byte(s)método.
21815
11
@tomasz Eu não prefiro fazer string <-> [] byte dessa maneira, apenas mostrando uma opção diferente :-) e sim, você está certo, eu entendi mal a pergunta.
Brandon Gao
Quando faço isso, o resultado é cap()de tamanho arbitrário, o que significa que está lendo na memória desconhecida. Para que isso seja correto, acho que você precisará alocar o reflect.SliceHeadertamanho completo e definir manualmente o cap. Algo assim: play.golang.org/p/fBK4dZM-qD
Lye Fish
E eu nem tenho certeza disso .------------- ^ - Talvez seja melhor: play.golang.org/p/NJUxb20FTG
Lye Fish
-1

Matrizes são valores ... fatias são mais como ponteiros. Isso é[n]type não é compatível []type, pois são fundamentalmente duas coisas diferentes. Você pode obter uma fatia que aponta para uma matriz usando o arr[:]que retorna uma fatia que possui arrao fazer backup do armazenamento.

Uma maneira de converter uma fatia de, por exemplo, []bytea [20]byteé realmente alocar um [20]byteque você pode fazer usando var [20]byte(como é um valor ... nãomake necessário) e, em seguida, copiar os dados para ele:

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

Essencialmente, o que muitas outras respostas dão errado é que []type NÃO é uma matriz.

[n]T e []T são coisas completamente diferentes!

Ao usar refletir []T não é do tipo Array, mas do tipo Slice e [n]Té do tipo Array.

Você também não pode usar map[[]byte]T mas pode usar map[[n]byte]T.

Às vezes, isso pode ser complicado porque muitas funções operam, por exemplo, []byteenquanto algumas funções retornam [n]byte(principalmente as funções hash crypto/*). Um hash sha256, por exemplo, é [32]bytee não é []byteassim quando os iniciantes tentam gravá-lo em um arquivo, por exemplo:

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

eles receberão um erro. A maneira correta de usar é

w.Write(sum[:])

No entanto, o que você quer? Apenas acessando a string bytewise? Você pode facilmente converter um stringem []byte:

bytes := []byte(str)

mas isso não é uma matriz, é uma fatia. Além disso byte,! = rune. Caso você queira operar com "caracteres", você precisa usar rune... não byte.

mroman
fonte