小编典典

从 io.Reader 到 Go 中的字符串

all

我有一个io.ReadCloser对象(来自一个http.Response对象)。

将整个流转换为对象的最有效方法是string什么?


阅读 110

收藏
2022-08-24

共1个答案

小编典典

编辑:

从 1.10 开始,strings.Builder 就存在了。例子:

buf := new(strings.Builder)
n, err := io.Copy(buf, r)
// check errors
fmt.Println(buf.String())

下面的过时信息

简短的回答是它效率不高,因为转换为字符串需要完整复制字节数组。这是执行您想要的操作的正确(非高效)方法:

buf := new(bytes.Buffer)
buf.ReadFrom(yourReader)
s := buf.String() // Does a complete copy of the bytes in the buffer.

此副本是作为保护机制完成的。字符串是不可变的。如果可以将 []byte 转换为字符串,则可以更改字符串的内容。但是,go 允许您使用 unsafe
包禁用类型安全机制。使用不安全的包需要您自担风险。希望这个名字本身就是一个足够好的警告。这是我使用不安全的方法:

buf := new(bytes.Buffer)
buf.ReadFrom(yourReader)
b := buf.Bytes()
s := *(*string)(unsafe.Pointer(&b))

我们开始了,您现在已经有效地将字节数组转换为字符串。真的,所有这些都是欺骗类型系统将其称为字符串。这种方法有几个注意事项:

  1. 不能保证这将适用于所有 go 编译器。虽然这适用于 plan-9 gc 编译器,但它依赖于官方规范中未提及的“实现细节”。您甚至不能保证这将适用于所有架构或不会在 gc 中更改。换句话说,这是一个坏主意。
  2. 该字符串是可变的!如果您对该缓冲区进行任何调用, 它将 更改字符串。要非常小心。

我的建议是坚持官方方法。做一个副本并不昂贵 也不值得不安全的危害。如果字符串太大而无法进行复制,则不应将其制成字符串。

2022-08-24