字符处理在内存差异的简单对比
1 简介
Go 和 Python 在内存中字符串的真实存储结构有什么不同,我们如何通过代码直观地“看见”这种差异?
本文从三步解释:
1️⃣ 先讲清楚理论上的区别(UTF-8 字节序列 vs Unicode 码点数组)
2️⃣ 用代码演示它了解这种区别
3️⃣ 最后解释这种差异背后的设计取舍
2、理论差异:UTF-8 字节序列 vs Unicode 码点数组
语言
Go 内存存储方式:UTF-8 字节序列(每个字符 1–4 字节)
举例(字符串):[240, 159, 145, 139, 228, 184, 150]
含义: 每个 Unicode 字符编码成变长字节序列
Python 3 内存存储方式:Unicode 码点数组(每个元素是整数)
举例(字符串):[128075, 19990]
含义:每个元素是一个 Unicode 码点(code point),不是字节
- 一句话说明:
Go 的 string 是 “字节流”,存的是 UTF-8 编码结果。
Python 的 str 是 “字符流”,存的是 Unicode 码点。
3、代码对比:直观看见底层结构
-
代码 Go 示例
package main import "fmt" func main() { s := "世" fmt.Println("字符串:", s) fmt.Println("len(s):", len(s)) // 字节数 fmt.Println("字节切片:", []byte(s)) // 查看 UTF-8 字节序列 fmt.Println("rune 切片:", []rune(s)) // 查看 Unicode 码点 }
输出:
字符串: 世
len(s): 7
字节切片: [240 159 145 139 228 184 150]
rune 切片: [128075 19990]
解释:
[228 184 150] 是 世 的 UTF-8 编码(3 字节);
[128075 19990] 是对应的 Unicode code points (U+1F44B,U+4E16)。
- Python 示例
s = “👋世”
print(“字符串:”, s)
print(“len(s):”, len(s)) # 字符数
print(“Unicode 码点列表:”, [ord(ch) for ch in s]) # 查看底层 code point
print(“UTF-8 字节序列:”, list(s.encode(‘utf-8’))) # 查看 UTF-8 编码结果
输出:
字符串: 👋世
len(s): 2
Unicode 码点列表: [128075, 19990]
UTF-8 字节序列: [240, 159, 145, 139, 228, 184, 150]
4、结果对比与图示
维度 Go Python
len(s) 7(字节) 2(字符)
内部存储 UTF-8 字节数组 Unicode 码点数组
[]byte(s) vs s.encode() [240,159,145,139,228,184,150] [240,159,145,139,228,184,150]
[]rune(s) vs [ord(ch) for ch in s] [128075,19990] [128075,19990]
- 内存结构示意图
Go (string = UTF-8 字节序列)
内存: [ F0 9F 91 8B E4 B8 96 ]
👋 (4字节) 世 (3字节)
Python (str = Unicode 码点数组)
内存: [ 0001F44B 00004E16 ]
👋 世
Go 追求与底层字节兼容,因此直接存 UTF-8;
Python 则抽象成 Unicode 码点序列,不受编码影响。
5 小结
-
设计哲学的取舍
设计目标 Go Python 效率 高效、节省内存、UTF-8 是通用标准编码 每个码点通常 2–4 字节,内存更多 易用性 需要开发者自己区分字节 vs 字符 直接按字符操作,简单直观 跨系统一致性 字节表示与文件/网络传输直接对应 不同平台内部都抽象为 Unicode 哲学口号 “显式优于隐式” (Explicit is better) “简单优于复杂” (Simple is better)
Go 的字符串是 UTF-8 字节流,处理底层数据高效但要开发者理解编码。
Python 的字符串是 Unicode 字符序列,开发者无需考虑编码,操作更自然。
- 点赞
- 收藏
- 关注作者
评论(0)