Cara menetapkan string ke array byte

375

Saya ingin menetapkan string ke array byte:

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

Punya metode lain?

sofire
sumber
11
Jika panjangnya strlebih besar dari panjangnya arrmaka Anda akan mendapatkan kesalahan "indeks di luar kisaran".
peterSO

Jawaban:

544

Aman dan sederhana:

[]byte("Here is a string....")
openwonk
sumber
14
Praktik pengkodean terbaik di Go menggunakan sepotong byte []bytedan bukan set array byte [20]bytesaat mengkonversi string ke byte ... Jangan percaya padaku? Lihat jawaban Rob Pike di utas ini
openwonk
9
OP bertanya tentang sebuah array, bukan sepotong. Dalam beberapa kasus, Anda perlu membatasi ukuran slice dan menggunakan array. Jawaban saya di bawah memangkas karakter tambahan untuk memastikan Anda tidak melimpahi array.
DavidG
3
Bagi mereka yang berpikir ini terlihat sedikit aneh: ini hanya ketik konversi di Go: golang.org/ref/spec#Coversions
Cnly
cara apa pun untuk menambahkan beberapa string dan menyatukannya? misalnya []byte("one", "two")?
rakim
Sayangnya tidak, @rakim, Anda hanya dapat melewatkan satu string ... jadi, Anda harus menggabungkannya terlebih dahulu atau menggabungkan beberapa irisan byte (di luar cakupan pertanyaan ini).
openwonk
149

Untuk mengkonversi dari string ke sepotong byte, string -> []byte:

[]byte(str)

Untuk mengkonversi array untuk sepotong, [20]byte -> []byte:

arr[:]

Untuk menyalin string ke array, string -> [20]byte:

copy(arr[:], str)

Sama seperti di atas, tetapi secara eksplisit mengkonversi string menjadi slice terlebih dahulu:

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

  • Built-in copyfungsi hanya salinan untuk sepotong, dari sepotong.
  • Array adalah "data dasar", sedangkan irisan adalah "viewport ke dalam data dasar".
  • Menggunakan [:] membuat array memenuhi syarat sebagai slice.
  • Sebuah string tidak memenuhi syarat sebagai slice yang dapat disalin ke , tapi itu memenuhi syarat sebagai slice yang dapat disalin dari (string yang berubah).
  • Jika string terlalu panjang, copyhanya akan menyalin bagian dari string yang cocok.

Kode ini:

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

... memberikan output berikut:

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

Saya juga membuatnya tersedia di Go Playground

Alexander
sumber
Anda mungkin ingin menambahkan contoh untuk mengonversi satu karakter. Saya menyimpulkan bahwa ini b[i] = []byte("A")[0]bekerja, tetapi b[i] = 'A'akhirnya menjadi jauh lebih bersih.
Alex Jansen
1
Itu tidak berfungsi untuk rune multi-byte:b[1] = '本'
Alexander
110

Sebagai contoh,

package main

import "fmt"

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

Keluaran:

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
sumber
3
Ini adalah satu-satunya jawaban yang benar-benar menjawab pertanyaan awal.
Jack O'Connor
Mengapa menetapkan 20 byte daripada spesifik tentang yang sebenarnya Anda butuhkan untuk string? Jika string membutuhkan kurang dari 20 bukankah itu sedikit tidak efisien? Dan juga rawan kesalahan jika melebihi 20?
Sir
1
@ Sir: Kami tidak menetapkan 20 byte. Kami menyalin 3 byte, panjangnya s, `Fungsi salin tidak bodoh. Menambah dan menyalin irisan : "Jumlah elemen yang disalin adalah minimum len (src) dan len (dst)."
peterSO
42

Sepotong kue:

arr := []byte("That's all folks!!")
Sameh Sharaf
sumber
8
Ini sepertinya tidak menjawab pertanyaan. OP ingin menulis byte string ke array yang ada yang mungkin lebih panjang dari string.
Jack O'Connor
2
Menggunakan irisan []bytelebih disukai daripada array [20]byte. Jawabannya benar berdasarkan praktik terbaik; jika spesifikasi atau kode memerlukan array, maka gunakan copysebaliknya (lihat contoh di tempat lain di utas ini).
openwonk
25

Saya pikir lebih baik ..

package main

import "fmt"

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

Periksa di sini: http://play.golang.org/p/vpnAWHZZk7

chespinoza
sumber
3
Itu tidak lebih baik. Itu salah. Tidak melakukan apa yang diminta pertanyaan itu.
peterSO
10

Pergi, konversikan string menjadi irisan byte

Anda memerlukan cara cepat untuk mengonversi string [] menjadi tipe [] byte. Untuk digunakan dalam situasi seperti menyimpan data teks ke file akses acak atau jenis manipulasi data lainnya yang membutuhkan data input berada dalam tipe byte [].

package main

func main() {

    var s string

    //...

    b := []byte(s)

    //...
}

yang berguna saat menggunakan ioutil.WriteFile, yang menerima irisan byte sebagai parameter datanya:

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

Contoh lain

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

Keluaran:

[104 101 108 108 111 32 119 111 114 108 100] halo dunia

Silakan periksa tautan bermain

ASHWIN RAJEEV
sumber
0

Akhirnya menciptakan metode khusus array untuk melakukan ini. Sama seperti paket encoding / binary dengan metode spesifik untuk setiap tipe int. Sebagai contoh 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)

Keluaran:

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

Perhatikan bagaimana saya ingin bantalan di sebelah kiri, bukan di kanan.

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

DavidG
sumber
3
Jika Anda tidak memilih, silakan tinggalkan komentar tentang mengapa Anda menemukan solusi tidak optimal atau bagaimana itu tidak relevan dengan pertanyaan OP.
DavidG
3
Saya pikir downvotes karena byte16PutStringmerupakan semacam implementasi ulang dari copyfungsi builtin , yang hanya mendukung membuat array baru daripada menggunakan yang sudah ada. copymemiliki dukungan kompiler khusus, sehingga dapat menangani berbagai jenis argumen, dan mungkin memiliki implementasi yang sangat berkinerja tinggi di bawah selimut. Juga, pertanyaan OP bertanya tentang menulis string ke array yang ada, daripada mengalokasikan yang baru, meskipun sebagian besar jawaban lain tampaknya mengabaikan itu juga ...
Jack O'Connor
Terima kasih @ JackO'Connor saya di sini untuk pembelajaran juga dan menghargai umpan balik yang membangun, bukan hanya downvote biasa.
DavidG
tidak tahu kamu memilihnya answerbenar semua orang di sini untuk belajar dan mendorong orang lain
muthukumar helius
-1

Selain metode yang disebutkan di atas, Anda juga dapat melakukan trik sebagai

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

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

Anda seharusnya tidak pernah menggunakan ini :-)

Brandon Gao
sumber
1
Ini gila. Saya pikir ini layak ditambahkan "tetapi Anda tidak boleh" di akhir tanggapan Anda. Terlepas dari kenyataan itu tidak benar-benar menjawab pertanyaan (OP berbicara tentang array byte, bukan irisan), Anda tampaknya tidak mendapatkan []byteobjek yang tepat menggunakan "konversi" Anda - gagal ketika Anda mencoba untuk mengubah p, lihat: play.golang.org/p/WHGl756ucj . Dalam kasus Anda, tidak yakin mengapa Anda lebih suka double-safe daripada b := []byte(s)metode ini.
tomasz
1
@ Thomasz Saya tidak suka melakukan byte <-> [] byte dengan cara ini, hanya menunjukkan opsi yang berbeda :-) dan ya Anda benar, saya salah paham pertanyaannya.
Brandon Gao
Ketika saya melakukan ini, hasilnya memiliki cap()ukuran sewenang-wenang, yang berarti membaca ke dalam memori yang tidak diketahui. Agar ini benar, saya pikir Anda harus memastikan Anda mengalokasikan reflect.SliceHeaderukuran penuh dan secara manual mengatur cap. Sesuatu seperti ini: play.golang.org/p/fBK4dZM-qD
Lye Fish
Dan saya bahkan tidak yakin akan hal itu .------------- ^ - Mungkin ini lebih baik: play.golang.org/p/NJUxb20FTG
Lye Fish
-1

Array adalah nilai ... irisan lebih seperti pointer. Itu adalah[n]type tidak sesuai dengan []typekarena mereka pada dasarnya adalah dua hal yang berbeda. Anda bisa mendapatkan slice yang menunjuk ke array dengan menggunakan arr[:]yang mengembalikan slice yang memiliki arrpenyimpanan backing.

Salah satu cara untuk mengkonversi sepotong misalnya []byteuntuk [20]byteadalah untuk benar-benar mengalokasikan [20]byteyang dapat Anda lakukan dengan menggunakanvar [20]byte (karena nilai ... tidak ada makeyang diperlukan) dan kemudian menyalin data ke dalamnya:

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

Pada dasarnya apa yang salah banyak jawaban lainnya adalah itu []typeBUKAN sebuah array.

[n]Tdan []Thal-hal yang sama sekali berbeda!

Saat menggunakan mencerminkan []T bukan dari jenis Array tetapi dari jenis Slice dan [n]Tjenis Array.

Anda juga tidak bisa menggunakan map[[]byte]T tetapi Anda bisa menggunakanmap[[n]byte]T .

Ini kadang-kadang bisa rumit karena banyak fungsi beroperasi misalnya di []bytesedangkan beberapa fungsi kembali [n]byte(terutama fungsi hash di crypto/*). Misalnya, hash sha256 adalah [32]bytedan tidak []bytedemikian ketika pemula mencoba menulisnya ke file misalnya:

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

mereka akan mendapatkan kesalahan. Cara yang benar adalah menggunakan

w.Write(sum[:])

Namun, apa yang Anda inginkan? Mengakses string secara langsung? Anda dapat dengan mudah mengonversi stringke []bytemenggunakan:

bytes := []byte(str)

tapi ini bukan sebuah array, ini adalah slice. Juga byte,! = rune. Jika Anda ingin beroperasi pada "karakter" yang perlu Anda gunakan rune... tidak byte.

mroman
sumber