如何将 []int8 转换为字符串
How to convert []int8 to string
从 []int8
转换为字符串的最佳方式(性能最快)是什么?
对于 []byte
我们可以做 string(byteslice)
,但是对于 []int8
它给出了一个错误:
cannot convert ba (type []int8) to type string
我从 *sqlx.Rows
的 SliceScan()
方法得到了 ba
,它产生 []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)
。
“Convert between slices of different types”可以肯定的是,您必须从原始 int8[]
.
构建正确的切片
我最终使用了 rune
(int32
别名)(playground), assuming that the uint8 were all simple ascii character. That is obviously an over-simplification and icza's 有更多相关信息。
另外 SliceScan() 方法最终返回 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
.
进行基准测试
不完全确定它是最快的,但我还没有发现更好的东西。
将 ba := []byte{}
更改为 ba := make([]byte,0, len(bs)
所以最后你有:
func B2S(bs []int8) string {
ba := make([]byte,0, len(bs))
for _, b := range bs {
ba = append(ba, byte(b))
}
return string(ba)
}
这样追加函数将永远不会尝试插入更多数据以适合切片的底层数组,您将避免不必要地复制到更大的数组。
事先注意: 提问者首先声明输入切片是 []int8
所以这就是答案的目的。后来他意识到输入是 []uint8
可以直接转换为 string
因为 byte
是 uint8
的别名(而 []byte
=> string
转换受 language spec) 支持。
您无法转换不同类型的切片,您必须手动进行。
问题是我们应该转换成什么类型的切片?我们有 2 个候选人:[]byte
和 []rune
。字符串在内部存储为 UTF-8 编码的字节序列([]byte
),一个 string
也可以转换为一段符文。该语言支持将这两种类型([]byte
和 []rune
)转换为 string
.
A rune
是一个 unicode 代码点。如果我们尝试以一对一的方式将 int8
转换为 rune
,如果输入包含编码为多个字节的字符(使用 UTF -8) 因为在这种情况下多个 int8
值应该在一个 rune
.
中结束
让我们从字符串"世界"
开始,它的字节是:
fmt.Println([]byte("世界"))
// Output: [228 184 150 231 149 140]
及其符文:
fmt.Println([]rune("世界"))
// [19990 30028]
只有2个符文和6个字节。所以显然 1 对 1 int8
->rune
映射不起作用,我们必须使用 1-1 int8
->byte
映射。
byte
是 uint8
的别名,范围为 0..255
,要将其转换为 []int8
(范围为 -128..127
),我们如果字节值大于 127,则必须使用 -256+bytevalue
,因此 []int8
中的 "世界"
string
如下所示:
[-28 -72 -106 -25 -107 -116]
我们想要的向后转换是:bytevalue = 256 + int8value
如果 int8
是负数但我们不能像 int8
(范围 -128。 .127) 而不是 byte
(范围 0..255),因此我们还必须先将其转换为 int
(最后返回 byte
)。这可能看起来像这样:
if v < 0 {
b[i] = byte(256 + int(v))
} else {
b[i] = byte(v)
}
但实际上,由于有符号整数是使用 2's complement 表示的,如果我们简单地使用 byte(v)
转换,我们会得到相同的结果(在负数的情况下,这是等效的到 256 + v
).
注意: 因为我们知道切片的长度,所以分配这个长度的切片并使用索引设置它的元素要快得多 []
和不调用内置 append
函数。
所以这是最终的转换:
func B2S(bs []int8) string {
b := make([]byte, len(bs))
for i, v := range bs {
b[i] = byte(v)
}
return string(b)
}
在 Go Playground 上试试。
使用不安全的包。
func B2S(bs []int8) string {
return strings.TrimRight(string(*(*[]byte)unsafe.Pointer(&bs)), "\x00")
}
再发一次^^
从 []int8
转换为字符串的最佳方式(性能最快)是什么?
对于 []byte
我们可以做 string(byteslice)
,但是对于 []int8
它给出了一个错误:
cannot convert ba (type []int8) to type string
我从 *sqlx.Rows
的 SliceScan()
方法得到了 ba
,它产生 []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)
。
“Convert between slices of different types”可以肯定的是,您必须从原始 int8[]
.
我最终使用了 rune
(int32
别名)(playground), assuming that the uint8 were all simple ascii character. That is obviously an over-simplification and icza's
另外 SliceScan() 方法最终返回 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
.
不完全确定它是最快的,但我还没有发现更好的东西。
将 ba := []byte{}
更改为 ba := make([]byte,0, len(bs)
所以最后你有:
func B2S(bs []int8) string {
ba := make([]byte,0, len(bs))
for _, b := range bs {
ba = append(ba, byte(b))
}
return string(ba)
}
这样追加函数将永远不会尝试插入更多数据以适合切片的底层数组,您将避免不必要地复制到更大的数组。
事先注意: 提问者首先声明输入切片是 []int8
所以这就是答案的目的。后来他意识到输入是 []uint8
可以直接转换为 string
因为 byte
是 uint8
的别名(而 []byte
=> string
转换受 language spec) 支持。
您无法转换不同类型的切片,您必须手动进行。
问题是我们应该转换成什么类型的切片?我们有 2 个候选人:[]byte
和 []rune
。字符串在内部存储为 UTF-8 编码的字节序列([]byte
),一个 string
也可以转换为一段符文。该语言支持将这两种类型([]byte
和 []rune
)转换为 string
.
A rune
是一个 unicode 代码点。如果我们尝试以一对一的方式将 int8
转换为 rune
,如果输入包含编码为多个字节的字符(使用 UTF -8) 因为在这种情况下多个 int8
值应该在一个 rune
.
让我们从字符串"世界"
开始,它的字节是:
fmt.Println([]byte("世界"))
// Output: [228 184 150 231 149 140]
及其符文:
fmt.Println([]rune("世界"))
// [19990 30028]
只有2个符文和6个字节。所以显然 1 对 1 int8
->rune
映射不起作用,我们必须使用 1-1 int8
->byte
映射。
byte
是 uint8
的别名,范围为 0..255
,要将其转换为 []int8
(范围为 -128..127
),我们如果字节值大于 127,则必须使用 -256+bytevalue
,因此 []int8
中的 "世界"
string
如下所示:
[-28 -72 -106 -25 -107 -116]
我们想要的向后转换是:bytevalue = 256 + int8value
如果 int8
是负数但我们不能像 int8
(范围 -128。 .127) 而不是 byte
(范围 0..255),因此我们还必须先将其转换为 int
(最后返回 byte
)。这可能看起来像这样:
if v < 0 {
b[i] = byte(256 + int(v))
} else {
b[i] = byte(v)
}
但实际上,由于有符号整数是使用 2's complement 表示的,如果我们简单地使用 byte(v)
转换,我们会得到相同的结果(在负数的情况下,这是等效的到 256 + v
).
注意: 因为我们知道切片的长度,所以分配这个长度的切片并使用索引设置它的元素要快得多 []
和不调用内置 append
函数。
所以这是最终的转换:
func B2S(bs []int8) string {
b := make([]byte, len(bs))
for i, v := range bs {
b[i] = byte(v)
}
return string(b)
}
在 Go Playground 上试试。
使用不安全的包。
func B2S(bs []int8) string {
return strings.TrimRight(string(*(*[]byte)unsafe.Pointer(&bs)), "\x00")
}
再发一次^^