问题描述
我只是问为什么Rust决定对字符串文字使用&str
而不是String
。 Rust能否仅将字符串文字自动转换为String
并放到堆中,而不是放到栈中?
解决方法
要理解其原因,请考虑Rust希望成为一种系统编程语言。通常,这意味着(除其他事项外)它必须(a)尽可能高效,并且(b)赋予程序员对堆内存分配和释放的完全控制权。 Rust的一种用例是内存非常有限的嵌入式编程。
因此,Rust不想在并非绝对必要的情况下分配堆内存。字符串文字在编译时是已知的,并且可以写入可执行文件/库的ro.data
节中,因此它们不会占用堆栈或堆空间。
现在,鉴于Rust不想在堆上分配值,它基本上被迫将字符串文字视为&str
:String
拥有自己的值并且可以移动和删除,但是如何删除ro.data
中的值?您实际上无法做到这一点,因此&str
是最合适的选择。
此外,将字符串文字视为&str
(或更准确地说是&'static str
)具有所有优点,而没有缺点。它们可以在多个地方使用,可以共享,而不必担心使用堆内存,并且永远不必删除。而且,它们可以随意转换为拥有的String
,因此始终可以将它们作为String
使用,但是您只在需要时付费。
要创建String
,您必须:
- 在堆上保留一个位置(分配),并且
- 将所需内容从只读位置复制到新分配的区域。
如果像"foo"
这样的字符串文字同时执行了两个操作,则每个字符串将被有效分配两次:一次在可执行文件内部作为只读字符串,另一次在堆上。您根本不能只引用可执行文件中存储的原始只读数据。
&str
文字使您可以访问最有效的字符串数据:启动时在可执行映像中存在的字符串数据,由编译器连同构成程序的指令放在此处。它指向的数据没有存储在堆栈上,而是分配给指针,只有像Rust slice那样的大小对。
将"foo"
的desugar改成现在的拼写"foo".to_owned()
会使其变慢,空间效率降低,并且可能需要另一语法才能获得非分配的{ {1}}。毕竟,您不希望&str
分配一个字符串只是为了立即将其丢弃。像Python这样的语言通过使字符串不可变来缓解这种情况,这使它们可以缓存源代码中提到的字符串。在Rust中,变异x == "foo"
通常是创建变异的全部要点,因此该策略将行不通。