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:[97989900000000000000000]([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)}
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)."
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).
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
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]byteif 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:
[0000000000000979899]
Remarquez comment je voulais un rembourrage à gauche, pas à droite.
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))))
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
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:
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.
str
est supérieure à la longueur de,arr
vous obtiendrez une erreur "index hors plage".Réponses:
Sûr et simple:
la source
[]byte
et non un ensemble de tableaux d'octets[20]byte
lors 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[]byte("one", "two")
?Pour convertir une chaîne en une tranche d'octets
string -> []byte
:Pour la conversion d' un tableau à une tranche,
[20]byte -> []byte
:Pour la copie d' une chaîne à un tableau,
string -> [20]byte
:Identique à ci-dessus, mais en convertissant explicitement la chaîne en tranche d'abord:
copy
fonction intégrée copie uniquement sur une tranche, à partir de une tranche.[:]
fait qu'un tableau peut être qualifié de tranche.copy
ne copiera que la partie de la chaîne qui convient.Ce code:
... donne la sortie suivante:
Je l'ai également rendu disponible sur le Go Playground
la source
b[i] = []byte("A")[0]
fonctionne, maisb[i] = 'A'
finit par être beaucoup plus propre.b[1] = '本'
Par exemple,
Production:
la source
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)."Part de gâteau:
la source
[]byte
est 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 à lacopy
place (voir les exemples ailleurs dans ce fil).Je pense que c'est mieux..
Vérifiez ici: http://play.golang.org/p/vpnAWHZZk7
la source
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.
ce qui est utile lorsque vous utilisez ioutil.WriteFile, qui accepte une tranche d'octets comme paramètre de données:
Un autre exemple
Production:
Veuillez vérifier le lien aire de jeux
la source
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)
.Production:
Remarquez comment je voulais un rembourrage à gauche, pas à droite.
http://play.golang.org/p/7tNumnJaiN
la source
byte16PutString
c'est une sorte de réimplémentation de lacopy
fonction intégrée , qui ne prend en charge que la création de nouveaux tableaux au lieu d'utiliser un existant.copy
a 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 ...answer
Outre les méthodes mentionnées ci-dessus, vous pouvez également faire un tour comme
Va jouer: http://play.golang.org/p/xASsiSpQmC
Vous ne devriez jamais utiliser ceci :-)
la source
[]byte
objet approprié en utilisant votre "conversion" - il échoue mal lorsque vous essayez de le modifierp
, voir: play.golang.org/p/WHGl756ucj . Dans votre cas, vous ne savez pas pourquoi vous préférez la double sécurité à lab := []byte(s)
méthode.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 lareflect.SliceHeader
taille maximale et définissez manuellement lecap
. Quelque chose comme ça: play.golang.org/p/fBK4dZM-qDLes tableaux sont des valeurs ... les tranches sont plus comme des pointeurs. Ce n'est
[n]type
pas compatible avec[]type
car ce sont fondamentalement deux choses différentes. Vous pouvez obtenir une tranche qui pointe vers un tableau en utilisantarr[:]
qui renvoie une tranche qui aarr
comme stockage de sauvegarde.Une façon de convertir une tranche de, par exemple,
[]byte
en[20]byte
est d'allouer réellement[20]byte
ce que vous pouvez faire en utilisantvar [20]byte
(car c'est une valeur ... pasmake
nécessaire), puis de copier des données dedans:Essentiellement, ce que beaucoup d'autres réponses se trompent, c'est que ce
[]type
n'est PAS un tableau.[n]T
et ce[]T
sont des choses complètement différentes!Lors de l'utilisation de la réflexion
[]T
n'est pas de type Array mais de type Slice et[n]T
de type Array.Vous ne pouvez pas non plus utiliser
map[[]byte]T
mais 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 danscrypto/*
). Un hachage sha256 par exemple l'est[32]byte
et ne l' est pas[]byte
lorsque les débutants essaient de l'écrire dans un fichier par exemple:ils obtiendront une erreur. La bonne façon est d'utiliser
Mais que veux-tu? Vous accédez simplement à la chaîne par octet? Vous pouvez facilement convertir un
string
en en[]byte
utilisant: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 utiliserrune
... pasbyte
.la source