我研究了String的源代码,发现它是用Vec实现的,它没有小对象优化的形式:

pub struct String {
    vec: Vec<u8>,
}

来自C++,在C++中,每个主要的标准库都使用std::string的短串优化(SSO),这令人惊讶. 字符串的许多用例都涉及非常短的字符串,例如:

  1. 如果您正在编写编译器,您将拥有关键字和标记的字符串,如"==""pub""delete"
  2. 如果要将枚举串行化,则所有常量名称通常都足够短,可以放入SSO缓冲区
  3. 如果使用格式字符串打印内容,格式字符串很少会长到无法放入SSO中
  4. 如果要解析具有键和值的配置文件,键和值通常都非常短,如setting: enabled
  5. 如果您存储的是正则表达式,那么这些正则表达式通常也适合SSO
  6. 如果你正在存储一本词典,那么几乎所有的词典都可以被SSO,因为例如,英语单词相当短

在这种情况下,默认的String不使用任何SSO的理由是什么?是否可以追溯添加该功能?有没有任何分析数据来证明SSO是否有帮助?

关于C++中SSO的注记

SSO是通过重用std::string容器的内存来完成的,否则这些内存将存储要存储的指针、大小和容量:

  • 内部字符串的大小(可以只有一个字节)
  • 容器中的字符串数据(通常最大长度为~20字节)

也有可能只重用容量,并且有一个指向字符串对象内部的指针. 所有这一切通常都是通过union完成的,在铁 rust 公司也是可能的.

推荐答案

SSO并不总是赢家-它以牺牲长字符串为代价来优化短字符串.铁 rust 更喜欢有一致的性能特征,特别是在标准库中,并让外部 crate 处理其他情况.这样,标准库的用户永远不会感到悲观,如果需要,他们可以使用外部 crate ,并且仍然可以享受针对其特定用例的优化.

此外,Rust中的SSO可能比C++中的SSO更昂贵:尽管我不知道C++中的标准库是否真正使用了这种功能,但C++具有移动构造函数-因此,无论数据存储在堆中还是堆栈中,都可以有指向数据的指针.这样,无需分支即可访问数据.然而,Rust不能做到这一点,因为当对象移动时,指向内联存储的指针必须更新-但在Rust中,移动总是简单的Memcpys.

此外,虽然Rust可以将String定义为具有SSO,但现在不可能定义为it guarantees the buffer will always be stored on the heapString::into_bytes() (that returns Vec<u8>) guarantees to not copy the data.

Rust相关问答推荐

有没有方法处理rust中嵌套的ok_or()?

无需通过ASIO输入音频,并使用cpal进行反馈示例

在Tauri中获取ICoreWebView 2_7以打印PDF

在一个tauri协议处理程序中调用一个rectuc函数的推荐技术是什么?

程序退出后只写入指定管道的数据

如何格式化传入Rust中mysql crate的Pool::new的字符串

使用极点数据帧时,找不到枚举结果的方法lazy()

我是否可以在Ruust中修改 struct 实例上的字符串,以使其在修改后具有相同的字符串生存期?

`RwLockWriteGuard_,T`不实现T实现的特征

根据填充系数以相对大小在给定空间中布局项目

期望一个具有固定大小 x 元素的数组,找到一个具有 y 元素的数组

Rust:为什么 &str 不使用 Into

随机函数不返回随机值

为什么这个闭包没有实现Fn?

部署Rust发布二进制文件的先决条件

为什么 Rust 允许写入不可变的 RwLock?

无法把握借来的价值不够长寿,请解释

使用 serde_json 进一步处理字段

从函数返回 u32 的数组/切片

如何断言代码不会在测试中编译?