从[]int8
转换为字符串的最佳方式(最快性能)是什么?
对于[]byte
,我们可以执行string(byteslice)
,但对于[]int8
,它会出错:
cannot convert ba (type []int8) to type string
我从[{3}}的ba
方法获得SliceScan()
生成[]int8
而不是string
这个解决方案最快吗?
func B2S(bs []int8) string {
ba := []byte{}
for _, b := range bs {
ba = append(ba, byte(b))
}
return string(ba)
}
编辑我的不好,是uint8
而不是int8
..所以我可以直接string(ba)
。
答案 0 :(得分:12)
事先注意:提问者首先声明输入切片为[]int8
,这就是答案所针对的。后来他意识到输入是[]uint8
,可以直接转换为string
,因为byte
是uint8
的别名([]byte
=> {{1 language spec)支持转换。
您无法转换不同类型的切片,您必须手动完成。
问题是我们应该转换为什么类型的切片?我们有2位候选人:string
和[]byte
。字符串在内部存储为UTF-8编码的字节序列([]rune
),而[]byte
也可以转换为符文切片。该语言支持将这两种类型(string
和[]byte
)转换为[]rune
。
string
是一个unicode代码点。如果我们尝试以一对一的方式将rune
转换为int8
,如果输入包含编码为多个字节的字符,则会失败(意味着输出错误)(使用UTF -8)因为在这种情况下,多个rune
值应该以{{1}}结尾。
让我们从字符串int8
开始,其字节为:
rune
它的符文:
"世界"
它只有2个符文和6个字节。因此,显然1对1 fmt.Println([]byte("世界"))
// Output: [228 184 150 231 149 140]
- > fmt.Println([]rune("世界"))
// [19990 30028]
映射不起作用,我们必须使用1-1 int8
- > rune
映射。< / p>
int8
是范围为byte
的{{1}}的别名,要将其转换为byte
(范围为uint8
)我们必须使用{ {1}}如果字节值为&gt; 127所以0..255
中的[]int8
-128..127
如下所示:
-256+bytevalue
向后转换我们想要的是:"世界"
如果string
为负数,但我们不能将此作为[]int8
(范围-128..127)和既不是[-28 -72 -106 -25 -107 -116]
(范围0..255),所以我们还必须先将其转换为bytevalue = 256 + int8value
(最后再转换为int8
)。这看起来像这样:
int8
但实际上由于有符号整数使用2's complement表示,如果我们只使用byte
转换,我们会得到相同的结果(如果是负数,则相当于{{1} }})。强>
注意:由于我们知道切片的长度,因此分配具有此长度的切片并使用索引int
设置其元素而不调用内置的切片要快得多在byte
函数中。
所以这是最后的转换:
if v < 0 {
b[i] = byte(256 + int(v))
} else {
b[i] = byte(v)
}
在Go Playground上尝试。
答案 1 :(得分:2)
不完全确定它是最快的,但我还没有找到更好的东西。
更改ba := []byte{}
的{{1}},以便最后:
ba := make([]byte,0, len(bs)
这样,append函数永远不会尝试插入更多可以放在切片底层数组中的数据,并且可以避免不必要的复制到更大的数组。
答案 2 :(得分:1)
“Convert between slices of different types”的确定是您必须从原始int8[]
构建正确的切片。
我最终使用rune
(int32
别名)(playground),假设uint8都是简单的ascii字符。这显然是一种过度简化,icza answer SliceScan()对此有更多的了解
另外,{{3}}方法最终还是返回uint8[]
。
package main
import (
"fmt"
)
func main() {
s := []int8{'a', 'b', 'c'}
b := make([]rune, len(s))
for i, v := range s {
b[i] = rune(v)
}
fmt.Println(string(b))
}
但我没有使用[]byte
对其进行基准测试。
答案 3 :(得分:0)
使用不安全的包裹。
func B2S(bs []int8) string {
return strings.TrimRight(string(*(*[]byte)unsafe.Pointer(&bs)), "\x00")
}
再次发送^^