Cách gán chuỗi cho mảng byte


375

Tôi muốn gán chuỗi cho mảng byte:

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

Có phương pháp nào khác?


11
Nếu độ dài strlớn hơn độ dài arrthì bạn sẽ gặp lỗi "chỉ số nằm ngoài phạm vi".
peterSO

Câu trả lời:


543

An toàn và đơn giản:

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

14
Thực hành mã hóa tốt nhất trong Go là sử dụng một lát byte []bytekhông phải là một mảng byte được thiết lập [20]bytekhi chuyển đổi chuỗi thành byte ... Bạn có tin tôi không? Kiểm tra câu trả lời của Rob Pike về chủ đề này
openwonk

9
OP hỏi về một mảng, không phải là một lát. Trong một số trường hợp, bạn cần giới hạn kích thước của lát và sử dụng một mảng thay thế. Câu trả lời của tôi dưới đây cắt bớt các ký tự phụ để đảm bảo bạn không tràn mảng.
DavidG

3
Đối với những người cho rằng điều này có vẻ hơi lạ: đây chỉ là loại chuyển đổi trong Go: golang.org/ref/spec#Conversions
Cnly 17/2/18

có cách nào để thêm nhiều chuỗi và nối chúng không? ví dụ []byte("one", "two")?
rakim

Thật không may, @rakim, bạn chỉ có thể truyền một chuỗi ... vì vậy, bạn phải nối chúng trước hoặc kết hợp nhiều lát byte (ngoài phạm vi của câu hỏi này).
openwonk

149

Để chuyển đổi từ một chuỗi thành một lát byte , string -> []byte:

[]byte(str)

Để chuyển đổi một mảng thành một lát , [20]byte -> []byte:

arr[:]

Để sao chép một chuỗi vào một mảng , string -> [20]byte:

copy(arr[:], str)

Tương tự như trên, nhưng trước tiên chuyển đổi chuỗi thành một lát:

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

  • Hàm tích hợp copychỉ sao chép vào một lát, từ một lát.
  • Mảng là "dữ liệu cơ bản", trong khi các lát cắt là "chế độ xem thành dữ liệu cơ bản".
  • Sử dụng [:]làm cho một mảng đủ điều kiện là một lát.
  • Một chuỗi không đủ điều kiện là một lát có thể được sao chép vào , nhưng nó đủ điều kiện là một lát có thể được sao chép từ (chuỗi là bất biến).
  • Nếu chuỗi quá dài, copysẽ chỉ sao chép phần của chuỗi phù hợp.

Mã này:

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

... Cho đầu ra sau:

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

Tôi cũng đã làm cho nó có sẵn tại Sân chơi Go


Bạn có thể muốn thêm một ví dụ để chuyển đổi một ký tự. Tôi đã suy luận từ điều này b[i] = []byte("A")[0]hoạt động, nhưng b[i] = 'A'cuối cùng sạch sẽ hơn nhiều.
Alex Jansen

1
Điều đó không hoạt động đối với các rune nhiều byte:b[1] = '本'
Alexander

110

Ví dụ,

package main

import "fmt"

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

Đầu ra:

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
Đây là câu trả lời duy nhất thực sự giải quyết câu hỏi ban đầu.
Jack O'Connor

Tại sao chỉ định 20 byte chứ không phải cụ thể về bạn thực sự cần cho chuỗi? Nếu chuỗi cần ít hơn 20 thì bit đó không hiệu quả? Và cũng dễ bị lỗi nếu vượt quá 20?
Thưa ngài,

1
@Sir: Chúng tôi không chỉ định 20 byte. Chúng tôi sao chép 3 byte, độ dài của s, Hàm `copy không bị câm. Nối và sao chép các lát : "Số phần tử được sao chép là tối thiểu của len (src) và len (dst)."
peterSO

42

Miếng bánh:

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

8
Điều này dường như không trả lời câu hỏi. OP muốn ghi các byte của chuỗi vào một mảng hiện có có thể dài hơn chuỗi.
Jack O'Connor

2
Sử dụng lát []byteđược ưa thích hơn mảng [20]byte. Trả lời là đúng dựa trên thực tiễn tốt nhất; nếu thông số kỹ thuật hoặc mã yêu cầu mảng, sau đó sử dụng copythay thế (xem ví dụ ở nơi khác trong chuỗi này).
openwonk

25

Tôi nghĩ nó tốt hơn..

package main

import "fmt"

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

Kiểm tra tại đây: http://play.golang.org/p/vpnAWHZZk7


3
Nó không tốt hơn. Nó sai. Nó không làm những gì câu hỏi yêu cầu.
peterSO

10

Đi, chuyển đổi một chuỗi thành một lát byte

Bạn cần một cách nhanh chóng để chuyển đổi một chuỗi [] thành [] kiểu byte. Để sử dụng trong các tình huống như lưu trữ dữ liệu văn bản vào tệp truy cập ngẫu nhiên hoặc loại thao tác dữ liệu khác yêu cầu dữ liệu đầu vào phải ở dạng byte [].

package main

func main() {

    var s string

    //...

    b := []byte(s)

    //...
}

hữu ích khi sử dụng ioutil.WriteFile, chấp nhận một lát byte làm tham số dữ liệu của nó:

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

Một vi dụ khac

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

Đầu ra:

[104 101 108 108 111 32 119 111 114 108 100] xin chào thế giới

Vui lòng kiểm tra sân chơi liên kết


0

Đã kết thúc việc tạo ra các phương thức cụ thể mảng để làm điều này. Giống như gói mã hóa / nhị phân với các phương thức cụ thể cho từng loại int. Ví dụ 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)

Đầu ra:

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

Chú ý cách tôi muốn đệm ở bên trái, không phải bên phải.

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


3
Nếu bạn không bình chọn câu trả lời, vui lòng để lại nhận xét về lý do tại sao bạn thấy giải pháp không tối ưu hoặc làm thế nào nó không liên quan đến câu hỏi của OP.
DavidG

3
Tôi nghĩ rằng các downvote là bởi vì byte16PutStringnó là một dạng tái hiện của copyhàm dựng sẵn , chỉ hỗ trợ tạo các mảng mới thay vì sử dụng một mảng hiện có. copycó hỗ trợ trình biên dịch đặc biệt, vì vậy nó có thể xử lý các loại đối số khác nhau và có lẽ nó có một triển khai hiệu năng thực sự cao dưới vỏ bọc. Ngoài ra, câu hỏi của OP đã hỏi về việc viết một chuỗi vào một mảng hiện có, thay vì phân bổ một chuỗi mới, mặc dù hầu hết các câu trả lời khác dường như cũng bỏ qua điều đó ...
Jack O'Connor

Cảm ơn @ JackO'Connor Tôi cũng ở đây vì đã học hỏi và đánh giá cao phản hồi mang tính xây dựng, không chỉ là downvote đơn giản.
DavidG

không biết rằng nó đã bỏ phiếu answerlà chính xác, mọi người đều ở đây để học hỏi và khuyến khích người khác
muthukumar helius

-1

Bên cạnh các phương pháp được đề cập ở trên, bạn cũng có thể thực hiện một mẹo như

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

Chơi: http://play.golang.org/p/xASsiSpQmC

Bạn không bao giờ nên sử dụng cái này :-)


1
Điều này là điên. Tôi nghĩ rằng nó đáng để thêm "nhưng bạn không nên" vào cuối câu trả lời của bạn. Ngoài thực tế là nó không thực sự trả lời câu hỏi (OP nói về mảng byte, không phải lát), bạn dường như không nhận được một []byteđối tượng phù hợp bằng cách sử dụng "chuyển đổi" của mình - nó thất bại nặng nề khi bạn cố gắng sửa đổi p, xem: play.golang.org/p/WHGl756ucj . Trong trường hợp của bạn, không chắc chắn lý do tại sao bạn thích không an toàn gấp đôi so với b := []byte(s)phương pháp.
tomasz

1
@tomasz Tôi không thích làm chuỗi <-> [] byte theo cách này, chỉ hiển thị một tùy chọn khác :-) và vâng bạn đúng, tôi đã hiểu nhầm câu hỏi.
Brandon Gao

Khi tôi làm điều này, kết quả có cap()kích thước tùy ý, có nghĩa là nó đọc vào bộ nhớ không xác định. Để điều này đúng, tôi nghĩ bạn cần đảm bảo rằng bạn phân bổ reflect.SliceHeaderkích thước đầy đủ và đặt thủ công cap. Một cái gì đó như thế này: play.golang.org/p/fBK4dZM-qD
Lye Fish

Và tôi thậm chí không chắc chắn về điều đó .------------- ^ - Có lẽ điều này tốt hơn: play.golang.org/p/NJUxb20FTG
Lye Fish

-1

Mảng là giá trị ... lát giống như con trỏ. Điều đó [n]typekhông tương thích []typevì về cơ bản chúng là hai thứ khác nhau. Bạn có thể nhận được một lát chỉ đến một mảng bằng cách sử dụng arr[:]trả về một lát có arrlưu trữ dự phòng.

Một cách để chuyển đổi một lát ví dụ []byteđể [20]bytelà để thực sự phân bổ một [20]bytemà bạn có thể làm bằng cách sử dụng var [20]byte(như đó là một giá trị ... không makecần thiết) và sau đó sao chép dữ liệu vào nó:

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

Về cơ bản, rất nhiều câu trả lời khác bị sai []typelà KHÔNG phải là một mảng.

[n]T[]Tlà những thứ hoàn toàn khác nhau!

Khi sử dụng phản chiếu []Tkhông phải là loại Array mà là loại Slice và [n]Tlà loại Array.

Bạn cũng không thể sử dụng map[[]byte]Tnhưng bạn có thể sử dụng map[[n]byte]T.

Điều này đôi khi có thể cồng kềnh vì rất nhiều hàm hoạt động chẳng hạn []bytetrong khi một số hàm trả về [n]byte(đáng chú ý nhất là các hàm băm trong crypto/*). Ví dụ, hàm băm sha256 là như vậy [32]bytevà không phải []bytevậy khi người mới bắt đầu cố gắng ghi nó vào một tệp chẳng hạn:

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

họ sẽ nhận được một lỗi. Cách chính xác là sử dụng

w.Write(sum[:])

Tuy nhiên, đó là những gì bạn muốn? Chỉ cần truy cập chuỗi bytewise? Bạn có thể dễ dàng chuyển đổi stringsang []bytesử dụng:

bytes := []byte(str)

nhưng đây không phải là một mảng, nó là một lát cắt. Ngoài ra , byte! = rune. Trong trường hợp bạn muốn thao tác trên "ký tự", bạn cần sử dụng rune... không byte.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.