Jak przypisać ciąg do tablicy bajtów

375

Chcę przypisać ciąg do tablicy bajtów:

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

Masz inną metodę?

sofire
źródło
11
Jeśli długość strjest większa niż długość arr, pojawi się błąd „indeks poza zakresem”.
peterSO,

Odpowiedzi:

543

Bezpieczny i prosty:

[]byte("Here is a string....")
openwonk
źródło
14
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)

... daje następujący wynik:

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

Udostępniłem go również na Go Playground

Alexander
źródło
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)
}

Wynik:

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
źródło
3
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)”.
peterSO
42

Bułka z masłem:

arr := []byte("That's all folks!!")
Sameh Sharaf
źródło
8
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).
openwonk
25

Myślę że to jest lepsze..

package main

import "fmt"

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

Sprawdź tutaj: http://play.golang.org/p/vpnAWHZZk7

chespinoza
źródło
3
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)))
}

Wynik:

[104 101 108 108 111 32 119 111 114 108 100] witaj świecie

Proszę sprawdzić link plac zabaw

ASHWIN RAJEEV
źródło
0

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

Wynik:

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

Zwróć uwagę, jak chciałem dopełnienie po lewej, a nie po prawej.

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

DavidG
źródło
3
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))))

Idź Graj: http://play.golang.org/p/xASsiSpQmC

Nigdy nie powinieneś tego używać :-)

Brandon Gao
źródło
1
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
Lye Fish
I nawet nie jestem tego pewien .------------- ^ - Może tak jest lepiej: play.golang.org/p/NJUxb20FTG
Lye Fish
-1

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:

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

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.

mroman
źródło