วิธีการกำหนดสตริงให้กับอาร์เรย์ไบต์


375

ฉันต้องการกำหนดสตริงให้กับอาร์เรย์ไบต์:

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

มีวิธีอื่นไหม


11
หากความยาวของstrมากกว่าความยาวของarrคุณจะได้รับข้อผิดพลาด "ดัชนีอยู่นอกช่วง"
peterSO

คำตอบ:


543

ปลอดภัยและเรียบง่าย:

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

14
แนวทางปฏิบัติในการเขียนโค้ดที่ดีที่สุดใน Go คือการใช้ส่วนของไบต์[]byteและไม่ใช่ชุดไบต์เป็นไบต์[20]byteเมื่อแปลงสตริงเป็นไบต์ ... อย่าเชื่อฉันเลย ลองดูคำตอบของ Rob Pike ในหัวข้อนี้
openwonk

9
OP ถามเกี่ยวกับอาเรย์ไม่ใช่ชิ้นส่วน ในบางกรณีคุณต้อง จำกัด ขนาดของชิ้นและใช้อาร์เรย์แทน คำตอบของฉันด้านล่างจดจ้องตัวอักษรพิเศษเพื่อให้แน่ใจว่าคุณจะไม่ล้นอาร์เรย์
DavidG

3
สำหรับผู้ที่คิดว่ามันดูแปลก ๆ นิดหน่อย: นี่เป็นเพียงแค่การแปลงใน Go: golang.org/ref/spec#Conversions
Cnly

มีวิธีใดบ้างในการเพิ่มสตริงจำนวนมากและต่อกันเป็นสตริง? เช่น[]byte("one", "two")?
rakim

น่าเสียดายที่ไม่ @rakim คุณสามารถส่งผ่านได้เพียงหนึ่งสายเท่านั้น ... ดังนั้นคุณต้องต่อกันก่อนหรือรวมไบต์หลาย ๆ ชุด (อยู่นอกขอบเขตของคำถามนี้)
openwonk

149

สำหรับการแปลงจากสตริงเป็นไบต์string -> []byte:

[]byte(str)

สำหรับการแปลงอาเรย์เป็นชิ้น[20]byte -> []byte:

arr[:]

สำหรับการคัดลอกสตริงไปยังอาร์เรย์string -> [20]byte:

copy(arr[:], str)

เหมือนข้างต้น แต่แปลงสตริงเป็นชิ้นอย่างชัดเจน:

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

  • copyฟังก์ชันในตัวคัดลอกไปยังชิ้นจากชิ้นเท่านั้น
  • อาร์เรย์คือ "ข้อมูลพื้นฐาน" ในขณะที่ชิ้นส่วนคือ "วิวพอร์ตเป็นข้อมูลพื้นฐาน"
  • การใช้[:]ทำให้อาร์เรย์มีคุณสมบัติเป็นชิ้น
  • สตริงไม่มีคุณสมบัติเป็นชิ้นที่สามารถคัดลอกไปยังแต่มันมีคุณสมบัติเป็นชิ้นที่สามารถคัดลอกจาก (สตริงไม่เปลี่ยนรูป)
  • หากสตริงยาวเกินไปcopyจะคัดลอกเฉพาะส่วนของสตริงที่พอดี

รหัสนี้:

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

... ให้ผลลัพธ์ต่อไปนี้:

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

ฉันยังให้บริการที่สนามเด็กเล่นโก


คุณอาจต้องการเพิ่มตัวอย่างสำหรับการแปลงอักขระเดี่ยว ฉันอนุมานจากสิ่งนี้ได้b[i] = []byte("A")[0]ผล แต่b[i] = 'A'จบลงด้วยความสะอาดกว่ามาก
Alex Jansen

1
ที่ไม่ทำงานสำหรับอักษรรูนแบบหลายไบต์:b[1] = '本'
อเล็กซานเดอร์

110

ตัวอย่างเช่น,

package main

import "fmt"

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

เอาท์พุท:

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
นี่เป็นคำตอบเดียวที่ตอบคำถามจริง
Jack O'Connor

เหตุใดจึงต้องกำหนด 20 ไบต์แทนที่จะเจาะจงเฉพาะคุณเกี่ยวกับสตริง หากสตริงต้องการน้อยกว่า 20 นั่นไม่ใช่บิตที่ไม่มีประสิทธิภาพใช่ไหม และยังเกิดข้อผิดพลาดได้ง่ายถ้ามันเกิน 20?
ท่านที่

1
@Sir: เราไม่ได้กำหนด 20 ไบต์ เราคัดลอก 3 ไบต์ความยาวsฟังก์ชัน `copy ไม่ได้เป็นใบ้ การผนวกและคัดลอกส่วนข้อมูล : "จำนวนองค์ประกอบที่คัดลอกคือขั้นต่ำของ len (src) และ len (dst)"
peterSO

42

เค้กชิ้น:

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

8
ดูเหมือนจะไม่ตอบคำถาม OP ต้องการเขียนไบต์ของสตริงไปยังอาร์เรย์ที่มีอยู่ซึ่งอาจยาวกว่าสตริง
Jack O'Connor

2
การใช้สไลซ์[]byteเป็นที่ต้องการมากกว่าอาร์เรย์ [20]byteคำตอบนั้นถูกต้องตามแนวทางปฏิบัติที่ดีที่สุด; ถ้าข้อมูลจำเพาะหรือรหัสจำเป็นต้องใช้อาร์เรย์ให้ใช้copyแทน (ดูตัวอย่างที่อื่นในหัวข้อนี้)
openwonk

25

ฉันคิดว่ามันจะดีกว่า ..

package main

import "fmt"

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

ตรวจสอบที่นี่: http://play.golang.org/p/vpnAWHZZk7


3
มันไม่ดีกว่า มันผิด. มันไม่ได้ทำในสิ่งที่คำถามถาม
peterSO

10

ไปแปลงสตริงเป็นชิ้นไบต์

คุณต้องการวิธีที่รวดเร็วในการแปลงสตริง [] เป็น [] ประเภทไบต์ เพื่อใช้ในสถานการณ์ต่าง ๆ เช่นการจัดเก็บข้อมูลข้อความลงในไฟล์การเข้าถึงแบบสุ่มหรือการจัดการข้อมูลประเภทอื่นที่ต้องการให้ข้อมูลอินพุตเป็น [] ชนิดไบต์

package main

func main() {

    var s string

    //...

    b := []byte(s)

    //...
}

ซึ่งมีประโยชน์เมื่อใช้ ioutil.WriteFile ซึ่งยอมรับการแบ่งไบต์เป็นพารามิเตอร์ข้อมูล:

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

ตัวอย่างอื่น

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

เอาท์พุท:

[104 101 108 108 111 32 119 111 114 108 100] สวัสดีชาวโลก

กรุณาตรวจสอบลิงค์สนามเด็กเล่น


0

จบลงด้วยการสร้างวิธีการเฉพาะของอาร์เรย์เพื่อทำสิ่งนี้ คล้ายกับแพ็คเกจการเข้ารหัส / ไบนารีด้วยวิธีการเฉพาะสำหรับแต่ละชนิด int 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)

เอาท์พุท:

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

สังเกตว่าฉันต้องการแพ็ดดิ้งทางซ้ายไม่ใช่ทางขวา

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


3
หากคุณลงคะแนนในคำตอบโปรดแสดงความคิดเห็นว่าทำไมคุณถึงพบว่าวิธีการแก้ปัญหาไม่เหมาะสมหรือไม่เกี่ยวข้องกับคำถามของ OP
DavidG

3
ฉันคิดว่า downvotes นั้นเป็นเพราะbyte16PutStringการจัดเรียงใหม่ของcopyฟังก์ชั่นbuiltin ที่รองรับเฉพาะการสร้างอาร์เรย์ใหม่แทนที่จะใช้ที่มีอยู่แล้ว copyมีการสนับสนุนคอมไพเลอร์พิเศษดังนั้นจึงสามารถจัดการกับประเภทของข้อโต้แย้งที่แตกต่างกันและอาจมีการใช้งานที่มีประสิทธิภาพสูงจริงๆภายใต้ฝาครอบ นอกจากนี้คำถามของ OP ยังถามเกี่ยวกับการเขียนสตริงไปยังอาร์เรย์ที่มีอยู่แทนที่จะจัดสรรสตริงใหม่แม้ว่าคำตอบอื่น ๆ ส่วนใหญ่ก็ดูเหมือนจะเพิกเฉยเช่นกัน ...
Jack O'Connor

ขอบคุณ @ JackO'Connor ฉันอยู่ที่นี่เพื่อการเรียนรู้เช่นกันและขอขอบคุณข้อเสนอแนะที่สร้างสรรค์ไม่ใช่แค่ downvote ธรรมดา
DavidG

ไม่ทราบว่าการโหวตลงanswerถูกต้องทุกคนอยู่ที่นี่เพื่อเรียนรู้และสนับสนุนผู้อื่น
muthukumar helius

-1

นอกเหนือจากวิธีการที่กล่าวข้างต้นคุณสามารถทำตาม

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

ไปเล่น: http://play.golang.org/p/xASsiSpQmC

คุณไม่ควรใช้ :-) นี้


1
มันบ้าไปแล้ว. ฉันคิดว่ามันคุ้มค่าที่จะเพิ่ม "แต่คุณไม่ควร" ในตอนท้ายของการตอบสนองของคุณ นอกเหนือจากข้อเท็จจริงที่ว่ามันไม่ได้ตอบคำถาม (OP พูดถึงอาร์เรย์ไบต์ไม่ใช่ชิ้น) คุณดูเหมือนจะไม่ได้รับ[]byteวัตถุที่เหมาะสมโดยใช้ "การแปลง" ของคุณ - มันล้มเหลวไม่ดีเมื่อคุณพยายามแก้ไขpดู: play.golang.org/p/WHGl756ucj ในกรณีของคุณไม่แน่ใจว่าทำไมคุณถึงต้องการสองครั้งที่ไม่ปลอดภัยมากกว่าb := []byte(s)วิธีนี้
tomasz

1
@ โทมัสฉันไม่ชอบที่จะทำสตริง <-> [] ไบต์ด้วยวิธีนี้เพียงแค่แสดงตัวเลือกอื่น :-) และใช่คุณพูดถูกฉันเข้าใจคำถามผิด
Brandon Gao

เมื่อฉันทำสิ่งนี้ผลลัพธ์จะมีcap()ขนาดตามอำเภอใจซึ่งหมายความว่ามันอ่านในหน่วยความจำที่ไม่รู้จัก สำหรับเรื่องนี้จะต้องมีสิทธิผมคิดว่าคุณจะต้องให้แน่ใจว่าคุณจัดสรรเต็มรูปแบบขนาดและการตั้งค่าด้วยตนเองreflect.SliceHeader capบางสิ่งเช่นนี้: play.golang.org/p/fBK4dZM-qD
Lye Fish

และฉันก็ไม่แน่ใจเหมือนกันว่า. --------- ^ - อาจจะดีกว่า: play.golang.org/p/NJUxb20FTG
Lye Fish

-1

อาร์เรย์เป็นค่า ... ตัวแบ่งเป็นเหมือนตัวชี้ ที่[n]typeไม่เข้ากันกับ[]typeพวกเขาเป็นสองสิ่งที่แตกต่างพื้นฐาน คุณสามารถได้รับชิ้นที่ชี้ไปที่อาร์เรย์โดยใช้arr[:]ที่ส่งกลับชิ้นที่มีarrมันเป็นที่เก็บข้อมูลสำรอง

วิธีหนึ่งที่จะแปลงชิ้นของตัวอย่างเช่น[]byteการ[20]byteคือการจัดสรรจริง[20]byteที่คุณสามารถทำโดยการใช้var [20]byte(ตามที่มันเป็นความคุ้มค่า ... ไม่makeจำเป็น) และคัดลอกข้อมูลลงในมัน

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

เป็นหลักสิ่งที่คำตอบอื่น ๆ มากมายผิดคือนั่น[]typeไม่ใช่อาเรย์

[n]Tและ[]Tเป็นสิ่งที่แตกต่างอย่างสิ้นเชิง!

เมื่อใช้การไตร่ตรอง[]Tไม่ได้เป็นอาเรย์ชนิดใด แต่เป็นชนิดสแลซและ[n]Tเป็นอาเรย์ที่มีเมตตา

นอกจากนี้คุณยังไม่สามารถใช้งานแต่คุณสามารถใช้map[[]byte]Tmap[[n]byte]T

นี้บางครั้งอาจจะยุ่งยากเพราะมากฟังก์ชั่นการใช้งานตัวอย่างเช่นใน[]byteขณะที่ฟังก์ชั่นบางส่วนจะกลับ[n]byte(ที่สะดุดตาที่สุดในฟังก์ชันแฮชcrypto/*) ตัวอย่างเช่นแฮช sha256 คือ[32]byteและไม่เป็น[]byteเช่นนั้นเมื่อผู้เริ่มต้นพยายามเขียนลงไฟล์เช่น:

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

พวกเขาจะได้รับข้อผิดพลาด วิธีที่ถูกต้องคือการใช้

w.Write(sum[:])

อย่างไรก็ตามคุณต้องการอะไร เพียงแค่เข้าถึงสตริง bytewise? คุณสามารถแปลงstringไป[]byteใช้:

bytes := []byte(str)

แต่นี่ไม่ใช่อาร์เรย์มันเป็นส่วนแบ่ง นอกจากนี้byte! = rune. ในกรณีที่คุณต้องการที่จะทำงานใน "ตัวละคร" คุณจำเป็นต้องใช้rune... byteไม่ได้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.