Rust 的 `String` 和 `str` 有什么区别?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24158114/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 02:18:42  来源:igfitidea点击:

What are the differences between Rust's `String` and `str`?

stringrust

提问by Daniel Fath

Why does Rust have Stringand str? What are the differences between Stringand str? When does one use Stringinstead of strand vice versa? Is one of them getting deprecated?

为什么 Rust 有Stringand strString和之间有什么区别str?什么时候使用String而不是,str反之亦然?其中之一是否已被弃用?

回答by huon

Stringis the dynamic heap string type, like Vec: use it when you need to own or modify your string data.

String是动态堆字符串类型,例如Vec:当您需要拥有或修改字符串数据时使用它。

stris an immutable1sequence of UTF-8 bytes of dynamic length somewhere in memory. Since the size is unknown, one can only handle it behind a pointer. This means that strmost commonly2appears as &str: a reference to some UTF-8 data, normally called a "string slice" or just a "slice". A sliceis just a view onto some data, and that data can be anywhere, e.g.

str是内存中某处动态长度的 UTF-8 字节的不可变1序列。由于大小未知,只能在指针后面处理。这意味着str最常见的2显示为&str:对某些 UTF-8 数据的引用,通常称为“字符串切片”或仅称为“切片”。切片只是一些数据的视图,该数据可以在任何地方,例如

  • In static storage: a string literal "foo"is a &'static str. The data is hardcoded into the executable and loaded into memory when the program runs.
  • Inside a heap allocated String: Stringdereferences to a &strviewof the String's data.
  • On the stack: e.g. the following creates a stack-allocated byte array, and then gets a view of that data as a &str:

    use std::str;
    
    let x: &[u8] = &[b'a', b'b', b'c'];
    let stack_str: &str = str::from_utf8(x).unwrap();
    
  • 在静态存储中:字符串文字"foo"&'static str. 数据被硬编码到可执行文件中,并在程序运行时加载到内存中。
  • 里面堆分配StringString解除引用到&str视图中的String“s的数据。
  • 在堆栈上:例如,以下创建一个堆栈分配的字节数组,然后将该数据&str视图作为一个

    use std::str;
    
    let x: &[u8] = &[b'a', b'b', b'c'];
    let stack_str: &str = str::from_utf8(x).unwrap();
    

In summary, use Stringif you need owned string data (like passing strings to other threads, or building them at runtime), and use &strif you only need a view of a string.

总之,String如果您需要拥有的字符串数据(例如将字符串传递给其他线程,或在运行时构建它们),请使用,&str如果您只需要字符串的视图,请使用。

This is identical to the relationship between a vector Vec<T>and a slice &[T], and is similar to the relationship between by-value Tand by-reference &Tfor general types.

这与 vectorVec<T>和 slice之间的关系相同&[T],也类似于一般类型的by-valueT和 by-reference之间的关系&T



1A stris fixed-length; you cannot write bytes beyond the end, or leave trailing invalid bytes. Since UTF-8 is a variable-width encoding, this effectively forces all strs to be immutable in many cases. In general, mutation requires writing more or fewer bytes than there were before (e.g. replacing an a(1 byte) with an ?(2+ bytes) would require making more room in the str). There are specific methods that can modify a &strin place, mostly those that handle only ASCII characters, like make_ascii_uppercase.

1Astr为定长;您不能在末尾写入字节,也不能留下尾随无效字节。由于 UTF-8 是可变宽度编码,因此str在许多情况下这有效地强制所有s 是不可变的。一般来说,mutation 需要写入比以前更多或更少的字节(例如,用(2+ 个a字节)替换(1 个?字节)需要在 中腾出更多空间str)。有一些特定的方法可以&str就地修改 a ,主要是那些只处理 ASCII 字符的方法,例如make_ascii_uppercase.

2Dynamically sized typesallow things like Rc<str>for a sequence of reference counted UTF-8 bytes since Rust 1.2. Rust 1.21 allows easily creating these types.

2自 Rust 1.2 以来,动态大小的类型允许诸如Rc<str>引用计数的 UTF-8 字节序列之类的事情。Rust 1.21 允许轻松创建这些类型。

回答by Luis Ayuso

I have a C++ background and I found it very useful to think about Stringand &strin C++ terms:

我有 C++ 背景,我发现思考String&str用 C++ 术语非常有用:

  • A Rust Stringis like a std::string; it owns the memory and does the dirty job of managing memory.
  • A Rust &stris like a char*(but a little more sophisticated); it points us to the beginning of a chunk in the same way you can get a pointer to the contents of std::string.
  • RustString就像一个std::string; 它拥有内存并完成管理内存的肮脏工作。
  • Rust&str就像一个char*(但更复杂一点);它将我们指向一个块的开始,就像你可以得到一个指向std::string.

Are either of them going to disappear? I do not think so. They serve two purposes:

他们中的任何一个都会消失吗?我不这么认为。它们有两个目的:

Stringkeeps the buffer and is very practical to use. &stris lightweight and should be used to "look" into strings. You can search, split, parse, and even replace chunks without needing to allocate new memory.

String保留缓冲区,使用起来非常实用。&str是轻量级的,应该用于“查看”字符串。您可以搜索、拆分、解析甚至替换块,而无需分配新内存。

&strcan look inside of a Stringas it can point to some string literal. The following code needs to copy the literal string into the Stringmanaged memory:

&str可以查看 a 的内部,String因为它可以指向某个字符串文字。以下代码需要将文字字符串复制到String托管内存中:

let a: String = "hello rust".into();

The following code lets you use the literal itself without copy (read only though)

以下代码可让您在不复制的情况下使用文字本身(不过是只读的)

let a: &str = "hello rust";

回答by Chris Morgan

str, only used as &str, is a string slice, a reference to a UTF-8 byte array.

str,仅用作&str,是一个字符串切片,一个对 UTF-8 字节数组的引用。

Stringis what used to be ~str, a growable, owned UTF-8 byte array.

String曾经是~str一个可增长的、拥有的 UTF-8 字节数组。

回答by Zorf

They are actually completely different. First off, a stris nothing but a type level thing; it can only be reasoned about at the type level because it's a so-called dynamically-sized type (DST). The size the strtakes up cannot be known at compile time and depends on runtime information — it cannot be stored in a variable because the compiler needs to know at compile time what the size of each variable is. A stris conceptually just a row of u8bytes with the guarantee that it forms valid UTF-8. How large is the row? No one knows until runtime hence it can't be stored in a variable.

它们实际上是完全不同的。首先, astr只是一个类型级别的东西;它只能在类型级别进行推理,因为它是所谓的动态大小类型 (DST)。str在编译时无法知道占用的大小,它取决于运行时信息——它不能存储在变量中,因为编译器需要在编译时知道每个变量的大小。Astr在概念上只是一行u8字节,并保证它形成有效的 UTF-8。行有多大?没有人知道直到运行时,因此它不能存储在变量中。

The interesting thing is that a &stror any other pointer to a strlike Box<str>doesexist at runtime. This is a so-called "fat pointer"; it's a pointer with extra information (in this case the size of the thing it's pointing at) so it's twice as large. In fact, a &stris quite close to a String(but not to a &String). A &stris two words; one pointer to a the first byte of a strand another number that describes how many bytes long the the stris.

有趣的是,&str或任何其他指针str一样Box<str>存在在运行时。这就是所谓的“胖指针”;它是一个带有额外信息的指针(在这种情况下是它指向的东西的大小),所以它是两倍大。事实上, a&str非常接近 a String(但不接近 a &String)。A&str是两个字;一个指向 a 的第一个字节str和另一个数字的指针,该数字描述了 a 的str长度。

Contrary to what is said, a strdoes not need to be immutable. If you can get a &mut stras an exclusive pointer to the str, you can mutate it and all the safe functions that mutate it guarantee that the UTF-8 constraint is upheld because if that is violated then we have undefined behaviour as the library assumes this constraint is true and does not check for it.

与所说的相反, astr不需要是不可变的。如果你可以得到 a&mut str作为指向 的独占指针str,你可以改变它,所有改变它的安全函数都保证支持 UTF-8 约束,因为如果违反了,那么我们就会有未定义的行为,因为库假设这个约束是true 并且不检查它。

So what is a String? That's threewords; two are the same as for &strbut it adds a third word which is the capacity of the strbuffer on the heap, always on the heap (a stris not necessarily on the heap) it manages before it's filled and has to re-allocate. the Stringbasically ownsa stras they say; it controls it and can resize it and reallocate it when it sees fit. So a Stringis as said closer to a &strthan to a str.

那么什么是String? 这是3个字; 两个与 for 相同,&str但它添加了第三个字,它是str堆上缓冲区的容量,总是在堆上(astr不一定在堆上),它在填充之前管理并且必须重新分配。在String基本拥有一个str像他们说的; 它控制它,可以调整它的大小并在它认为合适时重新分配它。所以 aString更接近于 a 而&str不是 a str

Another thing is a Box<str>; this also owns a strand its runtime representation is the same as a &strbut it also owns the strunlike the &strbut it cannot resize it because it does not know its capacity so basically a Box<str>can be seen as a fixed-length Stringthat cannot be resized (you can always convert it into a Stringif you want to resize it).

另一件事是Box<str>; this 也拥有 astr并且它的运行时表示与 a 相同&str但它也拥有str不同的&str但它不能调整它的大小因为它不知道它的容量所以基本上 aBox<str>可以被看作是一个String不能调整大小的固定长度(你可以String如果要调整大小,请始终将其转换为 a )。

A very similar relationship exists between [T]and Vec<T>except there is no UTF-8 constraint and it can hold any type whose size is not dynamic.

之间存在非常相似的关系[T]Vec<T>除了没有 UTF-8 约束并且它可以容纳大小不是动态的任何类型。

The use of stron the type level is mostly to create generic abstractions with &str; it exists on the type level to be able to conveniently write traits. In theory stras a type thing didn't need to exist and only &strbut that would mean a lot of extra code would have to be written that can now be generic.

str在类型级别上的使用主要是创建通用抽象&str;它存在于类型级别以便能够方便地编写特征。理论上,str作为一种类型的东西并不需要存在,&str但这意味着必须编写许多现在可以通用的额外代码。

&stris super useful to be able to to have multiple different substrings of a Stringwithout having to copy; as said a Stringownsthe stron the heap it manages and if you could only create a substring of a Stringwith a new Stringit would have to copied because everything in Rust can only have one single owner to deal with memory safety. So for instance you can slice a string:

&str能够拥有 a 的多个不同子字符串String而无需复制是非常有用的;作为所述String拥有str关于其管理的堆,如果你只能创建的子串String用新String那就要复制,因为一切都在鲁斯特只能有一个单一的所有者来处理内存的安全性。例如,您可以对字符串进行切片:

let string: String   = "a string".to_string();
let substring1: &str = &string[1..3];
let substring2: &str = &string[2..4];

We have two different substring strs of the same string. stringis the one that owns the actual full strbuffer on the heap and the &strsubstrings are just fat pointers to that buffer on the heap.

我们有str同一个字符串的两个不同的子字符串s。string是拥有str堆上实际完整缓冲区的那个,&str子字符串只是指向堆上该缓冲区的胖指针。

回答by Aperion

std::Stringis simply a vector of u8. You can find its definition in source code . It's heap-allocated and growable.

std::String只是 的向量u8。您可以在源代码中找到它的定义。它是堆分配和可增长的。

#[derive(PartialOrd, Eq, Ord)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct String {
    vec: Vec<u8>,
}

stris a primitive type, also called string slice. A string slice has fixed size. A literal string like let test = "hello world"has &'static strtype. testis a reference to this statically allocated string. &strcannot be modified, for example,

str是一种原始类型,也称为字符串 slice。字符串切片具有固定大小。像这样的文字字符串let test = "hello world"具有&'static str类型。test是对这个静态分配的字符串的引用。 &str不能修改,例如

let mut word = "hello world";
word[0] = 's';
word.push('\n');

strdoes have mutable slice &mut str, for example: pub fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str)

str确实有可变 slice &mut str,例如: pub fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str)

let mut s = "Per Martin-L?f".to_string();
{
    let (first, last) = s.split_at_mut(3);
    first.make_ascii_uppercase();
    assert_eq!("PER", first);
    assert_eq!(" Martin-L?f", last);
}
assert_eq!("PER Martin-L?f", s);

But a small change to UTF-8 can change its byte length, and a slice cannot reallocate its referent.

但是对 UTF-8 的一个小改动就可以改变它的字节长度,并且一个切片不能重新分配它的所指对象。

回答by 00imvj00

In easy words, Stringis datatype stored on heap (just like Vec), and you have access to that location.

简单来说,String是数据类型存储在堆上(就像Vec),并且您可以访问该位置。

&stris a slice type. That means it is just reference to an already present Stringsomewhere in the heap.

&str是切片类型。这意味着它只是对String堆中某处已经存在的引用。

&strdoesn't do any allocation at runtime. So, for memory reasons, you can use &strover String. But, keep in mind that when using &stryou might have to deal with explicit lifetimes.

&str在运行时不做任何分配。因此,出于内存原因,您可以使用&strover String。但是,请记住,在使用时&str您可能必须处理显式的生命周期。

回答by Squirrel

For C# and Java people:

对于 C# 和 Java 人员:

  • Rust' String=== StringBuilder
  • Rust's &str=== (immutable) string
  • 锈' String===StringBuilder
  • Rust 的&str===(不可变)字符串

I like to think of a &stras a view on a string, like an interned string in Java / C# where you can't change it, only create a new one.

我喜欢将 a&str视为字符串的视图,就像 Java / C# 中的实习字符串一样,您无法更改它,只能创建一个新字符串。

回答by Developer

Here is a quick and easy explanation.

这是一个快速而简单的解释。

String- A growable, ownable heap-allocated data structure. It can be coerced to a &str.

String- 一种可增长的、可拥有的堆分配数据结构。它可以被强制转换为&str.

str- is (now, as Rust evolves) mutable, fixed-length string that lives on the heap or in the binary. You can only interact with stras a borrowed type via a string slice view, such as &str.

str- 是(现在,随着 Rust 的发展)存在于堆或二进制文件中的可变的、固定长度的字符串。您只能str通过字符串切片视图作为借用类型进行交互,例如&str.

Usage considerations:

使用注意事项:

Prefer Stringif you want to own or mutate a string - such as passing the string to another thread, etc.

String如果您想拥有或改变字符串,则更喜欢- 例如将字符串传递给另一个线程等。

Prefer &strif you want to have a read-only view of a string.

&str如果您想拥有字符串的只读视图,则更喜欢。