Her*_*ton 16 string unicode utf-8 type-conversion go
所以很容易将a解码[]byte
为a []rune
(简单地转换为string
,然后转换为[]rune
非常好的工作,我假设它默认为utf8并且使用填充字节用于invalids).我的问题是 - 你怎么想把它解码[]rune
回[]byte
utf8形式?
我错过了什么或者我是否已经为我的每一个符文手动调用EncodeRune[]rune
?当然有一个编码器,我可以简单地传递Writer
给.
icz*_*cza 34
您可以简单地转换可以转换回的符文切片([]rune
).string
[]byte
例:
rs := []rune{'H', 'e', 'l', 'l', 'o', ' ', '?', '?'}
bs := []byte(string(rs))
fmt.Printf("%s\n", bs)
fmt.Println(string(bs))
Run Code Online (Sandbox Code Playgroud)
输出(在Go Playground上试试):
Hello ??
Hello ??
Run Code Online (Sandbox Code Playgroud)
的围棋规格:换算明确提到这种情况下:转换和从字符串类型,点#3:
将一片符文转换为字符串类型会产生一个字符串,该字符串是转换为字符串的各个符文值的串联.
请注意,上述解决方案 - 尽管可能是最简单的 - 可能不是最有效的.原因是它首先创建一个string
值,以UTF-8编码形式保存符文的"副本",然后将字符串的后备切片复制到结果字节切片(必须复制一个副本,因为string
值是不可变的,如果结果切片与之共享数据string
,我们就可以修改内容string
;有关详细信息,请参阅golang:[] byte(string)vs [] byte(*string)和不可变字符串和指针地址).
请注意,智能编译器可以检测到string
不能引用中间值,从而消除其中一个副本.
通过分配单个字节切片,我们可以获得更好的性能,并将符文逐个编码到其中.我们已经完成了.为了方便起见,我们可以打电话unicode/utf8
给我们帮助:
rs := []rune{'H', 'e', 'l', 'l', 'o', ' ', '?', '?'}
bs := make([]byte, len(rs)*utf8.UTFMax)
count := 0
for _, r := range rs {
count += utf8.EncodeRune(bs[count:], r)
}
bs = bs[:count]
fmt.Printf("%s\n", bs)
fmt.Println(string(bs))
Run Code Online (Sandbox Code Playgroud)
以上输出是一样的.在Go Playground尝试一下.
请注意,为了创建结果切片,我们必须猜测结果切片的大小.我们使用了最大估计,即符文数乘以符文可编码为(utf8.UTFMax
)的最大字节数.在大多数情况下,这将超过需要.
我们可能会创建第三个版本,我们首先计算所需的确切大小.为此,我们可以使用该utf8.RuneLen()
功能.增益将不会"浪费"内存,我们将不必做最后的切片(bs = bs[:count]
).
让我们比较一下表演.要比较的3个功能(3个版本):
func runesToUTF8(rs []rune) []byte {
return []byte(string(rs))
}
func runesToUTF8Manual(rs []rune) []byte {
bs := make([]byte, len(rs)*utf8.UTFMax)
count := 0
for _, r := range rs {
count += utf8.EncodeRune(bs[count:], r)
}
return bs[:count]
}
func runesToUTF8Manual2(rs []rune) []byte {
size := 0
for _, r := range rs {
size += utf8.RuneLen(r)
}
bs := make([]byte, size)
count := 0
for _, r := range rs {
count += utf8.EncodeRune(bs[count:], r)
}
return bs
}
Run Code Online (Sandbox Code Playgroud)
基准代码:
var rs = []rune{'H', 'e', 'l', 'l', 'o', ' ', '?', '?'}
func BenchmarkFirst(b *testing.B) {
for i := 0; i < b.N; i++ {
runesToUTF8(rs)
}
}
func BenchmarkSecond(b *testing.B) {
for i := 0; i < b.N; i++ {
runesToUTF8Manual(rs)
}
}
func BenchmarkThird(b *testing.B) {
for i := 0; i < b.N; i++ {
runesToUTF8Manual2(rs)
}
}
Run Code Online (Sandbox Code Playgroud)
结果如下:
BenchmarkFirst-4 20000000 95.8 ns/op
BenchmarkSecond-4 20000000 84.4 ns/op
BenchmarkThird-4 20000000 81.2 ns/op
Run Code Online (Sandbox Code Playgroud)
怀疑,第二个版本更快,第三个版本是最快的,虽然性能增益不是很大.一般来说,首选最简单的解决方案是首选,但如果这是您的应用程序的某些关键部分(并且执行了很多次),则第三个版本可能值得使用.
归档时间: |
|
查看次数: |
19778 次 |
最近记录: |