Najlepsze praktyki kodowania w Go to używanie kawałka bajtów, []bytea nie zestawu bajtów [20]bytepodczas konwersji łańcucha na bajty ... Nie wierzysz mi? Sprawdź odpowiedź Rob Pike na ten temat
openwonk
9
OP zapytał o tablicę, a nie plasterek. W niektórych przypadkach musisz ograniczyć rozmiar plasterka i zamiast tego użyć tablicy. Moja odpowiedź poniżej przycina dodatkowe znaki, aby upewnić się, że nie przepełnisz tablicy.
DavidG
3
Dla tych, którzy myślą, że wygląda to trochę dziwnie: jest to po prostu konwersja typu w Go: golang.org/ref/spec#Conversions
Cnly
jakikolwiek sposób, aby dodać wiele ciągów i połączyć je? na przykład []byte("one", "two")?
rakim
Niestety nie, @rakim, możesz przekazać tylko jeden ciąg ... więc musisz najpierw połączyć je lub połączyć wiele kawałków bajtów (poza zakresem tego pytania).
openwonk
149
Aby przekonwertować ciąg na plasterek bajtowy string -> []byte:
[]byte(str)
Aby przekonwertować tablicę na plasterek [20]byte -> []byte:
arr[:]
Aby skopiować ciąg do tablicy string -> [20]byte:
copy(arr[:], str)
To samo co powyżej, ale najpierw najpierw jawnie konwertuje ciąg na plasterek:
copy(arr[:],[]byte(str))
Wbudowana copyfunkcja kopiuje tylko do plasterka, z plasterka.
Tablice są „danymi bazowymi”, a wycinki są „rzutnią w dane bazowe”.
Użycie [:]powoduje, że tablica kwalifikuje się jako plasterek.
Łańcuch nie kwalifikuje się jako plaster, które mogą być kopiowane do , ale kwalifikuje się jako plaster, które mogą być kopiowane z (łańcuchy są niezmienne).
Jeśli łańcuch jest zbyt długi, copyskopiuje tylko część pasującą do łańcucha.
Ten kod:
var arr [20]byte
copy(arr[:],"abc")
fmt.Printf("array: %v (%T)\n", arr, arr)
Możesz dodać przykład konwersji pojedynczego znaku. Wydedukowałem z tego, że to b[i] = []byte("A")[0]działa, ale w b[i] = 'A'końcu jest o wiele czystsze.
Alex Jansen,
1
To nie działa na runy wielobajtowe:b[1] = '本'
Alexander
110
Na przykład,
package main
import"fmt"
func main(){
s :="abc"var a [20]byte
copy(a[:], s)
fmt.Println("s:",[]byte(s),"a:", a)}
To jedyna odpowiedź, która faktycznie odnosi się do pierwotnego pytania.
Jack O'Connor,
Po co przypisywać 20 bajtów, a nie konkretnie, o tym, że faktycznie potrzebujesz ciągu? Jeśli ciąg potrzebuje mniej niż 20, czy nie jest to trochę nieefektywne? A także podatny na błędy, jeśli przekracza 20?
Sir
1
@ Sir: Nie przypisujemy 20 bajtów. Kopiujemy 3 bajty, długość s, funkcja `copy nie jest głupia. Dołączanie i kopiowanie plasterków : „Liczba skopiowanych elementów to minimum len (src) i len (dst)”.
To nie wydaje się odpowiadać na pytanie. OP chciał zapisać bajty łańcucha do istniejącej tablicy, która może być dłuższa niż łańcuch.
Jack O'Connor,
2
Używanie plasterków []bytejest lepsze niż tablice [20]byte. Odpowiedź jest poprawna w oparciu o najlepsze praktyki; jeśli specyfikacja lub kod wymaga tablic, użyj copyzamiast tego (zobacz przykłady w innym miejscu tego wątku).
Nie jest lepiej. To jest źle. Nie robi tego, o co pytało pytanie.
peterSO
10
Idź, przekonwertuj ciąg na plasterek bajtów
Potrzebujesz szybkiego sposobu konwersji ciągu [] na typ bajtu []. Do użycia w sytuacjach, takich jak przechowywanie danych tekstowych w pliku o swobodnym dostępie lub innego rodzaju manipulowanie danymi, które wymaga, aby dane wejściowe były typu [] bajtowego.
package main
func main(){var s string//...
b :=[]byte(s)//...}
co jest przydatne podczas korzystania z ioutil.WriteFile, który przyjmuje wycinek bajtów jako parametr danych:
WriteFile func(filename string, data []byte, perm os.FileMode) error
Inny przykład
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)))}
Skończyło się tworzenie metod specyficznych dla tablicy, aby to zrobić. Podobnie jak pakiet kodowania / binarny z określonymi metodami dla każdego typu int. Na przykład 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)
Wynik:
[0000000000000979899]
Zwróć uwagę, jak chciałem dopełnienie po lewej, a nie po prawej.
Jeśli nie zgadzasz się na głosowanie, zostaw komentarz, dlaczego uważasz, że rozwiązanie nie jest optymalne lub w jaki sposób nie ma ono związku z pytaniem PO.
DavidG
3
Myślę, że negatywne opinie są spowodowane ponowną byte16PutStringimplementacją wbudowanej copyfunkcji, która obsługuje tylko tworzenie nowych tablic zamiast korzystania z istniejącej. copyma specjalną obsługę kompilatora, dzięki czemu może obsługiwać różne typy argumentów i prawdopodobnie ma naprawdę wydajną implementację pod przykryciem. Poza tym pytanie OP dotyczyło napisania ciągu do istniejącej tablicy, a nie przydzielenia nowego, chociaż większość innych odpowiedzi wydaje się też ignorować to ...
Jack O'Connor
Dzięki @ JackO'Connor Jestem tu również za naukę i doceniam konstruktywne opinie, a nie tylko zwykłe głosowanie.
DavidG
nie wiem, czy zostało odrzucone, answerjest poprawne, każde ciało jest tutaj, aby uczyć się i zachęcać innych
muthukumar helius,
-1
Oprócz metod wymienionych powyżej, możesz także zrobić trick
s :="hello"
b :=*(*[]byte)(unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&s))))
To jest szalone. Myślę, że warto dodać „ale nie powinieneś” na końcu swojej odpowiedzi. Poza tym, że tak naprawdę nie odpowiada na pytanie (OP mówi o tablicy bajtów, a nie o przekrojach), wydaje się, że nie otrzymujesz właściwego []byteobiektu za pomocą swojej „konwersji” - nie udaje się to przy próbie zmiany p, patrz: play.golang.org/p/WHGl756ucj . W twoim przypadku nie wiesz, dlaczego wolisz podwójne niebezpieczne od b := []byte(s)metody.
tomasz
1
@tomasz Nie wolę robić w ten sposób ciągu <-> [] bajtu, tylko pokazuję inną opcję :-) i tak, masz rację, źle zrozumiałem pytanie.
Brandon Gao,
Kiedy to robię, wynik ma cap()dowolną wielkość, co oznacza, że wczytuje się w nieznaną pamięć. Aby było to poprawne, myślę, że musisz upewnić się, że przydzielono pełny reflect.SliceHeaderrozmiar i ręcznie ustawiłeś cap. Coś w tym stylu: play.golang.org/p/fBK4dZM-qD
Tablice są wartościami ... plasterki bardziej przypominają wskaźniki. To [n]typenie jest zgodne, []typeponieważ są to zasadniczo dwie różne rzeczy. Możesz uzyskać wycinek, który wskazuje tablicę, używając tego, arr[:]który zwraca wycinek, który ma arrjako pamięć zapasową.
Jednym ze sposobów, aby przekształcić plasterek na przykład []bytena [20]byteto, aby rzeczywiście lokować [20]bytektóre można zrobić przy użyciu var [20]byte(jak jest to wartość ... nie makejest to konieczne), a następnie skopiować dane do niego:
Zasadniczo błędem jest wiele innych odpowiedzi, że []typeNIE jest to tablica.
[n]Ti []Tsą zupełnie innymi rzeczami!
Podczas używania odbicia []Tnie jest to rodzaj Array, ale rodzaj Slice i [n]Tjest to rodzaj Array.
Ty też nie możesz używać, map[[]byte]Tale możesz używać map[[n]byte]T.
Czasami może to być kłopotliwe, ponieważ wiele funkcji działa na przykład podczas, []bytegdy niektóre funkcje powracają [n]byte(w szczególności funkcje skrótu w crypto/*). Na przykład skrót mieszający sha256 jest [32]bytei nie jest []bytetak, gdy początkujący próbują zapisać go na przykład w pliku:
sum := sha256.Sum256(data)
w.Write(sum)
dostaną błąd. Prawidłowym sposobem jest użycie
w.Write(sum[:])
Czego jednak chcesz? Tylko dostęp do łańcucha znaków w inny sposób? Możesz łatwo przekonwertować a stringna []byte:
bytes :=[]byte(str)
ale to nie jest tablica, to kawałek. Również byte! = rune. Jeśli chcesz operować na „postaciach”, musisz użyć rune… nie byte.
str
jest większa niż długośćarr
, pojawi się błąd „indeks poza zakresem”.Odpowiedzi:
Bezpieczny i prosty:
źródło
[]byte
a nie zestawu bajtów[20]byte
podczas konwersji łańcucha na bajty ... Nie wierzysz mi? Sprawdź odpowiedź Rob Pike na ten temat[]byte("one", "two")
?Aby przekonwertować ciąg na plasterek bajtowy
string -> []byte
:Aby przekonwertować tablicę na plasterek
[20]byte -> []byte
:Aby skopiować ciąg do tablicy
string -> [20]byte
:To samo co powyżej, ale najpierw najpierw jawnie konwertuje ciąg na plasterek:
copy
funkcja kopiuje tylko do plasterka, z plasterka.[:]
powoduje, że tablica kwalifikuje się jako plasterek.copy
skopiuje tylko część pasującą do łańcucha.Ten kod:
... daje następujący wynik:
Udostępniłem go również na Go Playground
źródło
b[i] = []byte("A")[0]
działa, ale wb[i] = 'A'
końcu jest o wiele czystsze.b[1] = '本'
Na przykład,
Wynik:
źródło
s
, funkcja `copy nie jest głupia. Dołączanie i kopiowanie plasterków : „Liczba skopiowanych elementów to minimum len (src) i len (dst)”.Bułka z masłem:
źródło
[]byte
jest lepsze niż tablice[20]byte
. Odpowiedź jest poprawna w oparciu o najlepsze praktyki; jeśli specyfikacja lub kod wymaga tablic, użyjcopy
zamiast tego (zobacz przykłady w innym miejscu tego wątku).Myślę że to jest lepsze..
Sprawdź tutaj: http://play.golang.org/p/vpnAWHZZk7
źródło
Idź, przekonwertuj ciąg na plasterek bajtów
Potrzebujesz szybkiego sposobu konwersji ciągu [] na typ bajtu []. Do użycia w sytuacjach, takich jak przechowywanie danych tekstowych w pliku o swobodnym dostępie lub innego rodzaju manipulowanie danymi, które wymaga, aby dane wejściowe były typu [] bajtowego.
co jest przydatne podczas korzystania z ioutil.WriteFile, który przyjmuje wycinek bajtów jako parametr danych:
Inny przykład
Wynik:
Proszę sprawdzić link plac zabaw
źródło
Skończyło się tworzenie metod specyficznych dla tablicy, aby to zrobić. Podobnie jak pakiet kodowania / binarny z określonymi metodami dla każdego typu int. Na przykład
binary.BigEndian.PutUint16([]byte, uint16)
.Wynik:
Zwróć uwagę, jak chciałem dopełnienie po lewej, a nie po prawej.
http://play.golang.org/p/7tNumnJaiN
źródło
byte16PutString
implementacją wbudowanejcopy
funkcji, która obsługuje tylko tworzenie nowych tablic zamiast korzystania z istniejącej.copy
ma specjalną obsługę kompilatora, dzięki czemu może obsługiwać różne typy argumentów i prawdopodobnie ma naprawdę wydajną implementację pod przykryciem. Poza tym pytanie OP dotyczyło napisania ciągu do istniejącej tablicy, a nie przydzielenia nowego, chociaż większość innych odpowiedzi wydaje się też ignorować to ...answer
jest poprawne, każde ciało jest tutaj, aby uczyć się i zachęcać innychOprócz metod wymienionych powyżej, możesz także zrobić trick
Idź Graj: http://play.golang.org/p/xASsiSpQmC
Nigdy nie powinieneś tego używać :-)
źródło
[]byte
obiektu za pomocą swojej „konwersji” - nie udaje się to przy próbie zmianyp
, patrz: play.golang.org/p/WHGl756ucj . W twoim przypadku nie wiesz, dlaczego wolisz podwójne niebezpieczne odb := []byte(s)
metody.cap()
dowolną wielkość, co oznacza, że wczytuje się w nieznaną pamięć. Aby było to poprawne, myślę, że musisz upewnić się, że przydzielono pełnyreflect.SliceHeader
rozmiar i ręcznie ustawiłeścap
. Coś w tym stylu: play.golang.org/p/fBK4dZM-qDTablice są wartościami ... plasterki bardziej przypominają wskaźniki. To
[n]type
nie jest zgodne,[]type
ponieważ są to zasadniczo dwie różne rzeczy. Możesz uzyskać wycinek, który wskazuje tablicę, używając tego,arr[:]
który zwraca wycinek, który maarr
jako pamięć zapasową.Jednym ze sposobów, aby przekształcić plasterek na przykład
[]byte
na[20]byte
to, aby rzeczywiście lokować[20]byte
które można zrobić przy użyciuvar [20]byte
(jak jest to wartość ... niemake
jest to konieczne), a następnie skopiować dane do niego:Zasadniczo błędem jest wiele innych odpowiedzi, że
[]type
NIE jest to tablica.[n]T
i[]T
są zupełnie innymi rzeczami!Podczas używania odbicia
[]T
nie jest to rodzaj Array, ale rodzaj Slice i[n]T
jest to rodzaj Array.Ty też nie możesz używać,
map[[]byte]T
ale możesz używaćmap[[n]byte]T
.Czasami może to być kłopotliwe, ponieważ wiele funkcji działa na przykład podczas,
[]byte
gdy niektóre funkcje powracają[n]byte
(w szczególności funkcje skrótu wcrypto/*
). Na przykład skrót mieszający sha256 jest[32]byte
i nie jest[]byte
tak, gdy początkujący próbują zapisać go na przykład w pliku:dostaną błąd. Prawidłowym sposobem jest użycie
Czego jednak chcesz? Tylko dostęp do łańcucha znaków w inny sposób? Możesz łatwo przekonwertować a
string
na[]byte
:ale to nie jest tablica, to kawałek. Również
byte
! =rune
. Jeśli chcesz operować na „postaciach”, musisz użyćrune
… niebyte
.źródło