Comment attribuer une chaîne à un tableau d'octets


375

Je veux affecter une chaîne au tableau d'octets:

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

Vous avez une autre méthode?


11
Si la longueur de strest supérieure à la longueur de, arrvous obtiendrez une erreur "index hors plage".
peterSO

Réponses:


544

Sûr et simple:

[]byte("Here is a string....")

14
Les meilleures pratiques de codage dans Go utilisent une tranche d'octets []byteet non un ensemble de tableaux d'octets [20]bytelors de la conversion d'une chaîne en octets ... Vous ne me croyez pas? Découvrez la réponse de Rob Pike sur ce sujet
openwonk

9
L'OP a demandé un tableau, pas une tranche. Dans certains cas, vous devez limiter la taille de la tranche et utiliser un tableau à la place. Ma réponse ci-dessous coupe les caractères supplémentaires pour vous assurer de ne pas déborder le tableau.
DavidG

3
Pour ceux qui pensent que cela semble un peu étrange: il s'agit simplement d'une conversion de type dans Go: golang.org/ref/spec#Conversions
Cnly

est-il possible d'ajouter plusieurs chaînes et de les faire concaténer? par exemple []byte("one", "two")?
rakim

Malheureusement non, @rakim, vous ne pouvez transmettre qu'une seule chaîne ... vous devez donc d'abord les concaténer ou combiner plusieurs tranches d'octets (hors de la portée de cette question).
openwonk

149

Pour convertir une chaîne en une tranche d'octets string -> []byte:

[]byte(str)

Pour la conversion d' un tableau à une tranche, [20]byte -> []byte:

arr[:]

Pour la copie d' une chaîne à un tableau, string -> [20]byte:

copy(arr[:], str)

Identique à ci-dessus, mais en convertissant explicitement la chaîne en tranche d'abord:

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

  • La copyfonction intégrée copie uniquement sur une tranche, à partir de une tranche.
  • Les tableaux sont "les données sous-jacentes", tandis que les tranches sont "une fenêtre dans les données sous-jacentes".
  • L'utilisation [:]fait qu'un tableau peut être qualifié de tranche.
  • Une chaîne ne se qualifie pas comme une tranche qui peut être copié à , mais il est considéré comme une tranche qui peut être copié à partir ( les chaînes sont immuables).
  • Si la chaîne est trop longue, copyne copiera que la partie de la chaîne qui convient.

Ce code:

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

... donne la sortie suivante:

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

Je l'ai également rendu disponible sur le Go Playground


Vous voudrez peut-être ajouter un exemple de conversion d'un seul caractère. J'en ai déduit que cela b[i] = []byte("A")[0]fonctionne, mais b[i] = 'A'finit par être beaucoup plus propre.
Alex Jansen

1
Cela ne fonctionne pas pour les runes multi-octets:b[1] = '本'
Alexander

110

Par exemple,

package main

import "fmt"

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

Production:

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]

3
C'est la seule réponse qui répond réellement à la question d'origine.
Jack O'Connor

Pourquoi attribuer 20 octets plutôt que spécifique à propos de ce dont vous avez réellement besoin pour la chaîne? Si la chaîne a besoin de moins de 20, ce bit n'est-il pas inefficace? Et aussi sujette aux erreurs si elle dépasse 20?
Sir

1
@Sir: Nous n'affectons pas 20 octets. Nous copions 3 octets, la longueur de s, La fonction `copie n'est pas stupide. Ajout et copie de tranches : "Le nombre d'éléments copiés est le minimum de len (src) et len ​​(dst)."
peterSO

42

Part de gâteau:

arr := []byte("That's all folks!!")

8
Cela ne semble pas répondre à la question. OP voulait écrire les octets de la chaîne dans un tableau existant qui pourrait être plus long que la chaîne.
Jack O'Connor

2
L'utilisation de tranches []byteest préférable aux tableaux [20]byte. La réponse est correcte sur la base des meilleures pratiques; si les spécifications ou le code nécessitent des tableaux, utilisez-les à la copyplace (voir les exemples ailleurs dans ce fil).
openwonk

25

Je pense que c'est mieux..

package main

import "fmt"

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

Vérifiez ici: http://play.golang.org/p/vpnAWHZZk7


3
Ce n'est pas mieux. C'est faux. Il ne fait pas ce que la question demandait.
peterSO

10

Allez, convertissez une chaîne en une tranche d'octets

Vous avez besoin d'un moyen rapide pour convertir une chaîne [] en type [] octets. À utiliser dans des situations telles que le stockage de données texte dans un fichier à accès aléatoire ou tout autre type de manipulation de données qui nécessite que les données d'entrée soient de type [] octet.

package main

func main() {

    var s string

    //...

    b := []byte(s)

    //...
}

ce qui est utile lorsque vous utilisez ioutil.WriteFile, qui accepte une tranche d'octets comme paramètre de données:

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

Un autre exemple

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

Production:

[104 101 108 108 111 32 119 111 114 108 100] bonjour le monde

Veuillez vérifier le lien aire de jeux


0

Nous avons fini par créer des méthodes spécifiques aux tableaux pour ce faire. Tout comme le paquet encodage / binaire avec des méthodes spécifiques pour chaque type int. Par exemple 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)

Production:

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

Remarquez comment je voulais un rembourrage à gauche, pas à droite.

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


3
Si vous votez contre la réponse, veuillez laisser un commentaire sur les raisons pour lesquelles vous trouvez la solution non optimale ou en quoi elle n'est pas pertinente pour la question du PO.
DavidG

3
Je pense que les downvotes sont parce que byte16PutStringc'est une sorte de réimplémentation de la copyfonction intégrée , qui ne prend en charge que la création de nouveaux tableaux au lieu d'utiliser un existant. copya un support spécial du compilateur, donc il peut gérer différents types d'arguments, et il a probablement une implémentation très performante sous les couvertures. En outre, la question du PO portait sur l'écriture d'une chaîne dans un tableau existant, plutôt que sur l'allocation d'un nouveau, bien que la plupart des autres réponses semblent ignorer cela aussi ...
Jack O'Connor

Merci @ JackO'Connor Je suis ici aussi pour l'apprentissage et j'apprécie les commentaires constructifs, pas seulement le downvote.
DavidG

je ne sais pas si son vote answer
négatif

-1

Outre les méthodes mentionnées ci-dessus, vous pouvez également faire un tour comme

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

Va jouer: http://play.golang.org/p/xASsiSpQmC

Vous ne devriez jamais utiliser ceci :-)


1
C'est fou. Je pense que cela vaut la peine d'ajouter "mais vous ne devriez pas" à la fin de votre réponse. Mis à part le fait qu'il ne répond pas vraiment à la question (OP parle de tableau d'octets, pas de tranches), vous ne semblez pas obtenir un []byteobjet approprié en utilisant votre "conversion" - il échoue mal lorsque vous essayez de le modifier p, voir: play.golang.org/p/WHGl756ucj . Dans votre cas, vous ne savez pas pourquoi vous préférez la double sécurité à la b := []byte(s)méthode.
tomasz

1
@tomasz Je ne préfère pas faire de la chaîne <-> [] octets de cette façon, montrant simplement une option différente :-) et oui vous avez raison, j'ai mal compris la question.
Brandon Gao

Lorsque je fais cela, le résultat a une cap()taille arbitraire, ce qui signifie qu'il lit dans une mémoire inconnue. Pour que cela soit vrai, je pense que vous devez vous assurer que vous allouez la reflect.SliceHeadertaille maximale et définissez manuellement le cap. Quelque chose comme ça: play.golang.org/p/fBK4dZM-qD
Lye Fish

Et je n'en suis même pas certain .------------- ^ - Peut-être que c'est mieux: play.golang.org/p/NJUxb20FTG
Lye Fish

-1

Les tableaux sont des valeurs ... les tranches sont plus comme des pointeurs. Ce n'est [n]typepas compatible avec []typecar ce sont fondamentalement deux choses différentes. Vous pouvez obtenir une tranche qui pointe vers un tableau en utilisant arr[:]qui renvoie une tranche qui a arrcomme stockage de sauvegarde.

Une façon de convertir une tranche de, par exemple, []byteen [20]byteest d'allouer réellement [20]bytece que vous pouvez faire en utilisant var [20]byte(car c'est une valeur ... pas makenécessaire), puis de copier des données dedans:

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

Essentiellement, ce que beaucoup d'autres réponses se trompent, c'est que ce []typen'est PAS un tableau.

[n]Tet ce []Tsont des choses complètement différentes!

Lors de l'utilisation de la réflexion []Tn'est pas de type Array mais de type Slice et [n]Tde type Array.

Vous ne pouvez pas non plus utiliser map[[]byte]Tmais vous pouvez utilisermap[[n]byte]T .

Cela peut parfois être fastidieux car de nombreuses fonctions fonctionnent par exemple sur []byte tandis que certaines fonctions reviennent [n]byte(notamment les fonctions de hachage dans crypto/*). Un hachage sha256 par exemple l'est [32]byteet ne l' est pas []bytelorsque les débutants essaient de l'écrire dans un fichier par exemple:

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

ils obtiendront une erreur. La bonne façon est d'utiliser

w.Write(sum[:])

Mais que veux-tu? Vous accédez simplement à la chaîne par octet? Vous pouvez facilement convertir un stringen en []byteutilisant:

bytes := []byte(str)

mais ce n'est pas un tableau, c'est une tranche. Aussi byte!! rune. Dans le cas où vous souhaitez opérer sur des "personnages", vous devez utiliser rune... pas byte.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.