sofire
sofire

Reputation: 5807

How to assign string to bytes array

I want to assign string to bytes array:

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

Have another method?

Upvotes: 569

Views: 706290

Answers (10)

Carson
Carson

Reputation: 8148

If someone is looking for a quick consider use unsafe conversion between slices, you can refer to the following comparison.

package demo_test

import (
    "testing"
    "unsafe"
)

var testStr = "hello world"
var testBytes = []byte("hello world")

// Avoid copying the data.
func UnsafeStrToBytes(s string) []byte {
    return *(*[]byte)(unsafe.Pointer(&s))
}

// Avoid copying the data.
func UnsafeBytesToStr(b []byte) string {
    return *(*string)(unsafe.Pointer(&b))
}

func Benchmark_UnsafeStrToBytes(b *testing.B) {
    for i := 0; i < b.N; i++ {
        _ = UnsafeStrToBytes(testStr)
    }
}

func Benchmark_SafeStrToBytes(b *testing.B) {
    for i := 0; i < b.N; i++ {
        _ = []byte(testStr)
    }
}

func Benchmark_UnSafeBytesToStr(b *testing.B) {
    for i := 0; i < b.N; i++ {
        _ = UnsafeBytesToStr(testBytes)
    }
}

func Benchmark_SafeBytesToStr(b *testing.B) {
    for i := 0; i < b.N; i++ {
        _ = string(testBytes)
    }
}

go test -v -bench="^Benchmark" -run=none

output

cpu: Intel(R) Core(TM) i7-8565U CPU @ 1.80GHz
Benchmark_UnsafeStrToBytes
Benchmark_UnsafeStrToBytes-8    1000000000               0.2465 ns/op
Benchmark_SafeStrToBytes
Benchmark_SafeStrToBytes-8      289119562                4.181 ns/op
Benchmark_UnSafeBytesToStr
Benchmark_UnSafeBytesToStr-8    1000000000               0.2530 ns/op
Benchmark_SafeBytesToStr
Benchmark_SafeBytesToStr-8      342842938                3.623 ns/op
PASS

Upvotes: 2

openwonk
openwonk

Reputation: 15577

Safe and simple:

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

Upvotes: 809

Alexander
Alexander

Reputation: 10396

For converting from a string to a byte slice, string -> []byte:

[]byte(str)

For converting an array to a slice, [20]byte -> []byte:

arr[:]

For copying a string to an array, string -> [20]byte:

copy(arr[:], str)

Same as above, but explicitly converting the string to a slice first:

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

  • The built-in copy function only copies to a slice, from a slice.
  • Arrays are "the underlying data", while slices are "a viewport into underlying data".
  • Using [:] makes an array qualify as a slice.
  • A string does not qualify as a slice that can be copied to, but it qualifies as a slice that can be copied from (strings are immutable).
  • If the string is too long, copy will only copy the part of the string that fits (and multi-byte runes may then be copied only partly, which will corrupt the last rune of the resulting string).

This code:

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

...gives the following output:

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

I also made it available at the Go Playground

Upvotes: 270

ASHWIN RAJEEV
ASHWIN RAJEEV

Reputation: 2891

Go, convert a string to a bytes slice

You need a fast way to convert a []string to []byte type. To use in situations such as storing text data into a random access file or other type of data manipulation that requires the input data to be in []byte type.

package main

func main() {

    var s string

    //...

    b := []byte(s)

    //...
}

which is useful when using ioutil.WriteFile, which accepts a bytes slice as its data parameter:

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

Another example

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

Output:

[104 101 108 108 111 32 119 111 114 108 100] hello world

Please check the link playground

Upvotes: 15

mroman
mroman

Reputation: 1382

Arrays are values... slices are more like pointers. That is [n]type is not compatible with []type as they are fundamentally two different things. You can get a slice that points to an array by using arr[:] which returns a slice that has arr as it's backing storage.

One way to convert a slice of for example []byte to [20]byte is to actually allocate a [20]byte which you can do by using var [20]byte (as it's a value... no make needed) and then copy data into it:

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

Essentially what a lot of other answers get wrong is that []type is NOT an array.

[n]T and []T are completely different things!

When using reflect []T is not of kind Array but of kind Slice and [n]T is of kind Array.

You also can't use map[[]byte]T but you can use map[[n]byte]T.

This can sometimes be cumbersome because a lot of functions operate for example on []byte whereas some functions return [n]byte (most notably the hash functions in crypto/*). A sha256 hash for example is [32]byte and not []byte so when beginners try to write it to a file for example:

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

they will get an error. The correct way of is to use

w.Write(sum[:])

However, what is it that you want? Just accessing the string bytewise? You can easily convert a string to []byte using:

bytes := []byte(str)

but this isn't an array, it's a slice. Also, byte != rune. In case you want to operate on "characters" you need to use rune... not byte.

Upvotes: 1

DavidGamba
DavidGamba

Reputation: 3623

Ended up creating array specific methods to do this. Much like the encoding/binary package with specific methods for each int type. For example 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)

Output:

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

Notice how I wanted padding on the left, not the right.

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

Upvotes: 1

Sameh Sharaf
Sameh Sharaf

Reputation: 1141

Piece of cake:

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

Upvotes: 45

Brandon Gao
Brandon Gao

Reputation: 613

Besides the methods mentioned above, you can also do a trick as

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

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

You should never use this :-)

Upvotes: 0

chespinoza
chespinoza

Reputation: 2668

I think it's better..

package main

import "fmt"

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

Check here: http://play.golang.org/p/vpnAWHZZk7

Upvotes: 31

peterSO
peterSO

Reputation: 166925

For example,

package main

import "fmt"

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

Output:

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]

Upvotes: 125

Related Questions