我正在尝试将字节数组初始化为数字和字符串的混合。我已经设法使用一对追加或将字符串拆分为单独的字符来完成此操作,但为了可读性,是否有办法将其作为包含字符串的单个初始化程序来完成?
// method 1, with two appends
a := []byte{1, 2}
a = append(a, []byte("foo")...);
a = append(a, 3, 4);
// method 2, splitting the string into chars
b := []byte{1, 2, 'f', 'o', 'o', 3, 4)
最佳答案
你第一次尝试用 3 行写的内容可能比任何一行代码都更具可读性:
(您可以尝试 Go Playground 上的所有示例。)
// Doing one-by-one:
a := []byte{1, 2}
a = append(a, []byte("foo")...)
a = append(a, 3, 4)
fmt.Println(a)
// Using individual chars:
a = []byte{1, 2, 'f', 'o', 'o', 3, 4}
fmt.Println(a)
// Using a single string literal:
a = []byte("\x01\x02foo\x03\x04")
fmt.Println(a)
// Using several "nested" appends:
a = append(append([]byte{1, 2}, []byte("foo")...), 3, 4)
fmt.Println(a)
除非您创建辅助函数:
func concat(s ...[]byte) []byte {
var res []byte
for _, v := range s {
res = append(res, v...)
}
return res
}
然后使用它:
// With a utility function:
a = concat([]byte{1, 2}, []byte("foo"), []byte{3, 4})
fmt.Println(a)
// With a utility function, formatted differently:
a = concat(
[]byte{1, 2},
[]byte("foo"),
[]byte{3, 4},
)
fmt.Println(a)
您还可以使用单个键控复合文字和单个 copy()
调用来“插入”字符串:
// With keyed literal and copy:
a = []byte{1, 2, 5: 3, 4}
copy(a[2:], "foo")
fmt.Println(a)
我仍然不认为它更具可读性或更值得。
Concat 优化
根据下面留下的评论,@EliasVanOotegem 对上述解决方案进行了基准测试(在空 slice 上使用追加)并将其与所需字节 slice 的总容量相加并一次性分配该内存进行比较。后者的效率略高 (~20%),因此我将在下面包含该版本:
func concat(s ...[]byte) []byte {
c := 0
for _, v := range s {
c += len(v)
}
res := make([]byte, 0, c) // allocate everything
for _, v := range s {
res = append(res, v...)
}
return res
}
我个人会使用以下优化版本,它不需要 slice header 分配,因为它使用内置 copy()
:
func concat(s ...[]byte) []byte {
size := 0
for _, v := range s {
size += len(v)
}
res, i := make([]byte, size), 0
for _, v := range s {
i += copy(res[i:], v)
}
return res
}
关于string - 包含字符串文字的数组初始化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51363767/