Go 的魔法:string → []byte — 将字符串转换为字节数组的 3 种方法

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

引言:为什么 "How to assign string to bytes array" 这个问题如此受欢迎?

\n\n

如果你曾经用 Go (Golang) 编程,并且需要将普通字符串转换为字节数组 ([]byte),那么你并不孤单。Stack Overflow 上的问题 "How to assign string to bytes array" 获得了数万次浏览。看起来很简单,对吧?直接赋值就行了。但 Go 是一种强类型语言,你不能简单地将字符串直接赋值给字节切片。你需要掌握正确的技术。

\n\n

在本文中,我们将深入探讨 Go 中的 字符串到字节数组的转换。我将向你展示三种主要方法:从最简单的方法开始,到超快但危险的方法。你将了解如何根据任务选择合适的方法,并且再也不会在这些转换中感到困惑。

\n\n

我们开始吧!

\n\n

一点理论:为什么字符串不是字节数组?

\n\n

在开始写代码之前,让我们先弄清楚为什么 Go 要区分这两种类型。了解这一点可以帮你避免许多错误。

\n\n
    \n
  • string 在 Go 中是一个不可变的 (immutable) 字节序列。你不能通过索引更改字符串中的字符。字符串始终作为只读内存块存储。
  • \n
  • []byte 是一个可变的 (mutable) 字节切片。你可以修改其内容、添加新元素等。
  • \n
\n\n

正是由于这种“不可变性”的差异,Go 要求进行显式转换。如果编译器允许直接将字符串赋值给字节数组,你可能会意外修改字符串的“受保护”数据。因此,将字符串赋值给字节数组始终需要你明确的操作。

\n\n

方法 #1:显式类型转换(最简单)

\n\n

这是每个新手首先想到的方法。而且它确实有效!

\n\n
package main\n\nimport "fmt"\n\nfunc main() {\n    myString := "Привет, Go!"\n    myBytes := []byte(myString)\n\n    fmt.Println(myBytes) // [208 159 209 128 ...] — UTF-8 编码的字节\n    fmt.Println(string(myBytes)) // 转换回来:"Привет, Go!"\n}\n
\n\n

优点:

\n
    \n
  • 非常简单且可读性强。
  • \n
  • 标准方法,任何 Go 开发者都能理解。
  • \n
\n\n

缺点:

\n
    \n
  • 在内存中创建数据的新副本。如果字符串非常大(例如 10 MB),可能会在内存和时间上造成较大开销。
  • \n
  • 不适用于对每一纳秒都至关重要的高负载系统。
  • \n
\n\n

何时使用: 在 90% 的情况下。对于普通应用程序、Web 服务和脚本来说,这已经足够了。不要在不必要的地方进行优化。

\n\n

方法 #2:使用 copy()(可控)

\n\n

有时你已经预先分配了一个字节数组,并希望用字符串中的数据填充它。这时可以使用 copy 函数。

\n\n
package main\n\nimport "fmt"\n\nfunc main() {\n    myString := "Go is awesome"\n    \n    // 创建一个所需长度的字节切片\n    myBytes := make([]byte, len(myString))\n    \n    // 将字符串中的数据复制到切片中\n    n := copy(myBytes, myString)\n    \n    fmt.Printf("复制的字节数:%d\\n", n) // 13\n    fmt.Println(string(myBytes)) // "Go is awesome"\n}\n
\n\n

请注意:copy 只复制目标切片能容纳的字节数。如果目标切片比字符串短,则只复制其长度。如果你不确定大小,这比显式转换更安全。

\n\n

优点:

\n
    \n
  • 完全控制复制过程。
  • \n
  • 安全性:不会超出数组边界。
  • \n
  • 可用于部分复制(子字符串)。
  • \n
\n\n

缺点:

\n
    \n
  • 需要预先分配内存 (make)。
  • \n
  • 仍然会创建数据的副本。

博客

书籍推荐