530

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?

sofire
  • 5,417
  • 2
  • 14
  • 4
  • 11
    If the length of `str` is greater than the length of `arr` then you will get an "index out of range" error. – peterSO Nov 07 '11 at 04:13
  • 1
    `[]byte(“abc”)` to set a string to a bytes slice. See https://stackoverflow.com/a/62740786/12817546.`string(b)` or a `fmt.Sprintf("%s", b)` to set a bytes slice to a sting. See https://stackoverflow.com/a/62725637/12817546. –  Jul 09 '20 at 07:00

10 Answers10

731

Safe and simple:

[]byte("Here is a string....")
openwonk
  • 14,023
  • 7
  • 43
  • 39
  • 16
    Best coding practices in Go is using a slice of bytes `[]byte` and __not__ a set array of bytes `[20]byte` when converting a string to bytes... Don't believe me? Check out Rob Pike's answer on [this thread](https://groups.google.com/forum/#!topic/golang-nuts/84GCvDBhpbg) – openwonk Feb 14 '16 at 00:44
  • 18
    The OP asked about an array, not a slice. In some cases you need to limit the size of the slice and use an array instead. My answer below trims the extra chars to make sure you do not overflow the array. – DavidGamba Feb 14 '16 at 05:17
  • 11
    For those who think this looks a little bit strange: this is just type conversion in Go: https://golang.org/ref/spec#Conversions – Cnly Feb 17 '18 at 14:08
  • 1
    any way to add multiple strings and have them concatenated? eg `[]byte("one", "two")`? –  Feb 07 '20 at 19:17
  • 2
    Unfortunately no, @rakim, you can only pass one string... so, you have to concatenate them first or combine multiple slices of bytes (outside scope of this question). – openwonk Feb 09 '20 at 14:41
  • And of course the magic ingredient when translating abstract text to a byte sequence is the text encoding of choice! Some might wonder: which text encoding is applied here? That's a great question! It is UTF-8 in this case, because in Golang "string literals always contain UTF-8 text as long as they have no byte-level escapes". – Dr. Jan-Philip Gehrcke Jan 20 '21 at 16:01
  • This is converting to a slice, not to an array. – Alexander Sep 11 '21 at 06:33
  • @user12211419 yes, with append: `fmt.Printf("%s\n", append([]byte("he"), []byte("llo")...))` – Alexander Jan 26 '22 at 14:30
  • 1
    @user12211419: `[]byte("one" + "two")` – Jeff Learman Jul 16 '23 at 16:13
255

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

Alexander
  • 9,737
  • 4
  • 53
  • 59
  • You might want to add an example for converting a single character. I deduced from this that `b[i] = []byte("A")[0]` works, but `b[i] = 'A'` ends up being much cleaner. – Alex Jansen Dec 05 '19 at 02:03
  • 3
    That does not work for multi-byte runes: `b[1] = '本'` – Alexander Jan 11 '20 at 11:29
  • one question remains open that nobody has answered is: does `[]byte(str)` creates new underlying array with `make()` or not ? Or is it just returning a pointer copy to the original string. – Nulik Jan 18 '21 at 02:49
  • 1
    @Nulik Using https://godbolt.org I see that `[]byte(str)` calls the `runtime.stringtoslicebyte` function. `stringtoslicebyte` will allocate memory if needed and then call `copy`. See: [string.go](https://golang.org/src/runtime/string.go). The `copy` function copies bytes in a loop. – Alexander Jul 29 '21 at 14:56
123

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]
peterSO
  • 158,998
  • 31
  • 281
  • 276
  • 3
    This is the only answer that actually addresses the original question. – Jack O'Connor Aug 19 '16 at 14:43
  • Why assign 20 bytes rather than specific about you actually need for the string ? If the string needs less than 20 isn't that bit inefficient? And also error prone if it exceeds 20 ? – Sir Nov 19 '17 at 22:03
  • 1
    @Sir: We don't assign 20 bytes. We copy 3 bytes, the length of `s`, The `copy function is not dumb. [Appending to and copying slices](https://golang.org/ref/spec#Appending_and_copying_slices): "The number of elements copied is the minimum of len(src) and len(dst)." – peterSO Nov 19 '17 at 22:51
45

Piece of cake:

arr := []byte("That's all folks!!")
Sameh Sharaf
  • 1,103
  • 1
  • 13
  • 15
  • 9
    This doesn't seem to be answering the question. OP wanted to write the string's bytes to an existing array that might be longer than the string. – Jack O'Connor Aug 19 '16 at 14:35
  • 2
    Using slices `[]byte` is preferred over arrays `[20]byte`. Answer is correct based on best practices; if specifications or code necessitates arrays, then use `copy` instead (see examples elsewhere in this thread). – openwonk Apr 06 '17 at 21:18
31

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

chespinoza
  • 2,638
  • 1
  • 23
  • 46
15

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

ASHWIN RAJEEV
  • 2,525
  • 1
  • 18
  • 24
1

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

Brandon Gao
  • 623
  • 5
  • 9
  • 3
    This is crazy. I think it's worth adding "but you should not" at the end of your response. Apart from the fact it doesn't really answer the question (OP talks about bytes array, not slices), you don't seem to get a proper `[]byte` object using your "conversion" – it fails badly when you try to amend `p`, see: http://play.golang.org/p/WHGl756ucj. In your case, not sure why you would prefer double-unsafe over the `b := []byte(s)` method. – tomasz Jul 20 '15 at 11:57
  • 1
    @tomasz I'm not prefer to do string <-> []byte in this way, just showing a different option :-) and yes you are right, I misunderstood the question. – Brandon Gao Jul 20 '15 at 16:05
  • When I do this, the result has a `cap()` of arbitrary size, which means it's reading into unknown memory. For this to be right, I think you'd need to make sure you allocate the full `reflect.SliceHeader` size and manually set the `cap`. Something like this: https://play.golang.org/p/fBK4dZM-qD – Lye Fish Dec 31 '16 at 02:50
  • And I'm not even certain of that.-------------^-- Maybe this is better: https://play.golang.org/p/NJUxb20FTG – Lye Fish Dec 31 '16 at 03:04
  • I agree you probably shouldn't do this, but in theory the reason would be to avoid allocation. []byte(str) allocates a copy (except in certain cases where the compiler can optimize and eliminate the copy) – Andrew McKinlay Jun 16 '21 at 14:31
1

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

DavidGamba
  • 3,503
  • 2
  • 30
  • 46
  • 4
    I think the downvotes are because `byte16PutString` is a sort-of reimplementation of the builtin `copy` function, that only supports creating new arrays instead of using an existing one. `copy` has special compiler support, so it can handle different types of arguments, and it probably has a really high-performance implementation under the covers. Also, the OP's question asked about writing a string to an existing array, rather than allocating a new one, though most of the other answers seem to be ignoring that too... – Jack O'Connor Aug 19 '16 at 14:41
1

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.

mroman
  • 1,354
  • 9
  • 14
0

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
Carson
  • 6,105
  • 2
  • 37
  • 45