如何将字符串分配给字节数组


375

我想将字符串分配给字节数组:

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

还有其他方法吗?


11
如果的长度str大于的长度,arr则将出现“索引超出范围”错误。
peterSO 2011年

Answers:


542

安全简单:

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

14
Go中的最佳编码实践是在将字符串转换为字节时使用一片字节,[]byte不是一组字节数组[20]byte……不相信我吗?在此线程
openwonk 2016年

9
OP询问的是数组,而不是切片。在某些情况下,您需要限制切片的大小并改用数组。我在下面的回答会修剪多余的字符,以确保您不会溢出数组。
DavidG '16

3
对于那些谁认为这看起来有点怪:这是去只是类型转换: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功能只复制片,片。
  • 数组是“基础数据”,而切片是“基础数据的视口”。
  • 使用[:]使数组有资格作为切片。
  • 一个字符串,没有资格作为可以复制一个切片,但是它有资格作为可复制切片(string是不可改变的)。
  • 如果字符串太长,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)

我还在Go Playground上提供了它


您可能想添加一个转换单个字符的示例。我从中得出结论b[i] = []byte("A")[0],但b[i] = 'A'最终变得更加干净。
Alex Jansen

1
这不适用于多字节符文:b[1] = '本'
Alexander

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
这是实际解决原始问题的唯一答案。
杰克·奥康纳

为什么要分配20个字节而不是具体指定您实际需要的字符串?如果字符串需要小于20,那位效率不高吗?如果超过20,也容易出错?
爵士

1
@先生:我们不分配20个字节。我们复制3个字节(长度为)s,`复制功能并不笨拙。附加并复制切片:“复制的元素数是len(src)和len(dst)的最小值。”
peterSO

42

小菜一碟:

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

8
这似乎无法回答问题。OP希望将字符串的字节写入到可能比字符串更长的现有数组中。
杰克·奥康纳

2
使用切片[]byte比使用数组要优先[20]byte。根据最佳实践,答案是正确的;如果规范或代码需要数组,copy请改用(请参见本线程其他地方的示例)。
openwonk


10

去,将字符串转换为字节片

您需要一种将[]字符串转换为[] byte类型的快速方法。在诸如将文本数据存储到随机访问文件中或需要输入数据为[] byte类型的其他类型的数据操作的情况下使用。

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

输出:

[10410110810811132119119114108100]你好世界

请检查链接游乐场


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
我认为下降的原因byte16PutString是对内置copy函数的某种重新实现,它仅支持创建新数组而不使用现有数组。copy具有特殊的编译器支持,因此它可以处理不同类型的参数,并且可能在幕后具有真正的高性能实现。此外,OP的问题询问是否将字符串写入现有数组,而不是分配新的字符串,尽管其他大多数答案似乎也忽略了这一点……
Jack O'Connor

谢谢@ JackO'Connor我也在这里学习,感谢建设性的反馈,而不仅仅是普通的不赞成。
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 2015年

1
@tomasz我不喜欢以这种方式执行字符串<-> [] byte,只是显示一个不同的选项:-),是的,您是对的,我误解了这个问题。
布兰登·高

当我这样做时,结果具有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,不是Array类型,而是Slice和[n]TArray类型。

您也不能使用,map[[]byte]T但可以使用map[[n]byte]T

有时这会很麻烦,因为许多函数例如都在上运行,[]byte而某些函数会返回[n]byte(最显着的是中的哈希函数crypto/*)。例如,sha256哈希[32]byte不是[]byte,而在初学者尝试将其写入文件时,则不是:

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

他们会得到一个错误。正确的方法是使用

w.Write(sum[:])

但是,您想要什么?只是按字节访问字符串?您可以轻松地将转换string[]byte使用:

bytes := []byte(str)

但这不是数组,而是切片。另外,byte!= rune。如果要对“字符”进行操作,则需要使用rune...而不是byte

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.