为什么Rust有String和str?String和str之间有什么区别?什么时候使用String而不是str,反之亦然?其中一个被弃用了吗?
当前回答
我有C++背景,我发现用C++术语思考String和&str非常有用:
Rust字符串类似于std::String;它拥有内存并执行管理内存的肮脏工作。Rust&str就像char*(但有点复杂);它以同样的方式将我们指向块的开头,您可以获得指向std::string内容的指针。
他们中的任何一个都会消失吗?我不这么认为。它们有两个目的:
字符串保留缓冲区,使用起来非常实用&str是轻量级的,应该用来“查看”字符串。您可以搜索、拆分、解析甚至替换块,而无需分配新的内存。
&str可以查看字符串内部,因为它可以指向某个字符串文本。以下代码需要将文本字符串复制到字符串管理的内存中:
let a: String = "hello rust".into();
以下代码允许您在没有副本的情况下使用文字本身(尽管是只读的):
let a: &str = "hello rust";
其他回答
在Rust中,str是一种表示Unicode标量值序列的原始类型,也称为字符串切片。这意味着它是字符串的只读视图,它不拥有它所指向的内存。另一方面,string是一种可增长的、可变的、拥有的字符串类型。这意味着当您创建字符串时,它将在堆上分配内存以存储字符串的内容,并且当字符串超出范围时,它会释放该内存。因为String是可增长的和可变的,所以您可以在创建String之后更改它的内容。
通常,str在您想要引用存储在另一个数据结构(如string)中的字符串片段时使用。当您想要创建和拥有字符串值时,使用字符串。
简单地说,String是存储在堆上的数据类型(就像Vec一样),您可以访问该位置。
&str是一种切片类型。这意味着它只是对堆中某个已经存在的String的引用。
&str在运行时不进行任何分配。因此,出于内存原因,可以在字符串上使用&str。但是,请记住,在使用&str时,您可能需要处理显式的生存期。
str,仅用作&str,是一个字符串片段,是对UTF-8字节数组的引用。
字符串过去是~str,一个可增长的、拥有的UTF-8字节数组。
这里有一个简单快捷的解释。
字符串-可增长的、可拥有的堆分配数据结构。它可以强制为&str。
str是(现在,随着Rust的发展)可变的固定长度字符串,存在于堆或二进制文件中。只能通过字符串切片视图(如&str)将str作为借用类型进行交互。
使用注意事项:
如果您想拥有或变异字符串,请首选字符串,例如将字符串传递给另一个线程等。
如果希望字符串的只读视图,请首选&str。
它们实际上完全不同。首先,str只是一个类型级别的东西;它只能在类型级别进行推理,因为它是所谓的动态大小类型(DST)。str所占的大小在编译时无法得知,并且取决于运行时信息-它不能存储在变量中,因为编译器需要在编译时知道每个变量的大小。str在概念上只是一行u8字节,并保证它形成有效的UTF-8。这排有多大?在运行时之前没有人知道,因此它不能存储在变量中。
有趣的是,在运行时确实存在一个&str或任何其他指向str的指针,如Box<str>。这就是所谓的“胖指针”;它是一个带有额外信息的指针(在本例中是指它所指向的对象的大小),因此它的大小是它的两倍。事实上,&str非常接近字符串(但不是&String)。A&str是两个单词;一个指针指向str的第一个字节,另一个数字描述str的长度。
与所说的相反,str不需要是不可变的。如果您可以获取一个&mut str作为str的独占指针,那么您可以对它进行变异,并且所有变异它的安全函数都可以保证支持UTF-8约束,因为如果违反了这一约束,那么我们就有未定义的行为,因为库假定此约束为真,并且不检查它。
那么什么是字符串?这是三个字;两个与&str相同,但它添加了第三个字,即堆上str缓冲区的容量,总是在堆上(str不一定在堆上),它在填充之前管理,并且必须重新分配。String基本上拥有一个str;它控制它,可以调整大小,并在合适时重新分配。因此,正如所说,字符串更接近&str而不是str。
另一件事是Box<str>;它还拥有一个str,其运行时表示形式与&str相同,但它也拥有与&str不同的str,但它无法调整其大小,因为它不知道其容量,所以基本上Box<str>可以被视为一个固定长度的字符串,无法调整大小(如果要调整大小,可以始终将其转换为String)。
[T]和Vec<T>之间存在非常相似的关系,只是没有UTF-8约束,它可以容纳任何大小不是动态的类型。
在类型级别上使用str主要是使用&str;它存在于类型级别,以便能够方便地书写特征。理论上,str作为一种类型的东西不需要存在,只需要&str,但这意味着需要编写很多额外的代码,这些代码现在可以是通用的。
&str非常有用,可以在不复制的情况下拥有一个字符串的多个不同子字符串;正如所说,String拥有它管理的堆上的str,如果您只能用新的String创建String的子字符串,则必须复制它,因为Rust中的所有内容只能有一个所有者来处理内存安全问题。例如,您可以对字符串进行切片:
let string: String = "a string".to_string();
let substring1: &str = &string[1..3];
let substring2: &str = &string[2..4];
我们有两个相同字符串的不同子字符串str。字符串是拥有堆上实际完整str缓冲区的字符串,&str子字符串只是堆上缓冲区的胖指针。
推荐文章
- 如何删除表中特定列的第一个字符?
- 我应该如何从字符串中删除所有的前导空格?- - - - - -斯威夫特
- 将整数转换为字符串,以逗号表示千
- 将JavaScript字符串中的多个空格替换为单个空格
- printf()和puts()在C语言中的区别是什么?
- jQuery -替换字符串中某个字符的所有实例
- Base64长度计算?
- 使用split("|")按管道符号拆分Java字符串
- Std::cin输入空格?
- Rust中的默认函数参数
- 我如何在c++中创建一个随机的字母数字字符串?
- 如何使用JavaScript大写字符串中每个单词的第一个字母?
- Java中的split()方法对点(.)不起作用。
- 我如何检查如果一个变量是JavaScript字符串?
- 如何显示有两个小数点后的浮点数?