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


当前回答

在Rust中,str是一种表示Unicode标量值序列的原始类型,也称为字符串切片。这意味着它是字符串的只读视图,它不拥有它所指向的内存。另一方面,string是一种可增长的、可变的、拥有的字符串类型。这意味着当您创建字符串时,它将在堆上分配内存以存储字符串的内容,并且当字符串超出范围时,它会释放该内存。因为String是可增长的和可变的,所以您可以在创建String之后更改它的内容。

通常,str在您想要引用存储在另一个数据结构(如string)中的字符串片段时使用。当您想要创建和拥有字符串值时,使用字符串。

其他回答

锈蚀和字符串(&S)


字符串:

Rust拥有String类型,字符串本身存在于堆中,因此是可变的,可以更改其大小和内容。因为当拥有字符串的变量超出范围时,String是被拥有的,所以堆上的内存将被释放。String类型的变量是胖指针(指针+相关元数据)fat指针长度为3*8字节(字大小),由以下3个元素组成:指向堆上实际数据的指针,它指向第一个字符字符串长度(字符数)堆上字符串的容量

&字符串:

Rust非拥有的String类型,默认情况下是不可变的。字符串本身位于内存中的其他位置,通常位于堆或“静态内存”中。因为当&str变量超出范围时,字符串是非所有的,所以字符串的内存不会被释放。&str类型的变量是胖指针(指针+相关元数据)fat指针长度为2*8字节(字大小),由以下2个元素组成:指向堆上实际数据的指针,它指向第一个字符字符串长度(字符数)

例子:

use std::mem;

fn main() {
    // on 64 bit architecture:
    println!("{}", mem::size_of::<&str>()); // 16
    println!("{}", mem::size_of::<String>()); // 24

    let string1: &'static str = "abc";
    // string will point to `static memory which lives through the whole program

    let ptr = string1.as_ptr();
    let len = string1.len();

    println!("{}, {}", unsafe { *ptr as char }, len); // a, 3
    // len is 3 characters long so 3
    // pointer to the first character points to letter a

    {
        let mut string2: String = "def".to_string();

        let ptr = string2.as_ptr();
        let len = string2.len();
        let capacity = string2.capacity();
        println!("{}, {}, {}", unsafe { *ptr as char }, len, capacity); // d, 3, 3
        // pointer to the first character points to letter d
        // len is 3 characters long so 3
        // string has now 3 bytes of space on the heap

        string2.push_str("ghijk"); // we can mutate String type, capacity and length will aslo change
        println!("{}, {}", string2, string2.capacity()); // defghijk, 8

    } // memory of string2 on the heap will be freed here because owner goes out of scope

}

对于C#和Java用户:

Rust‘String==StringBuilderRust的&str==(不可变)字符串

我喜欢将&str视为字符串的视图,就像Java/C#中的一个内部字符串,您不能更改它,只能创建一个新字符串。

一些用法

示例1.rs

fn main(){
  let hello = String::("hello");
  let any_char = hello[0];//error
}

示例_2.rs

fn main(){
  let hello = String::("hello");
  for c in hello.chars() {
    println!("{}",c);
  }
}

示例_3.rs

fn main(){
  let hello = String::("String are cool");
  let any_char = &hello[5..6]; // = let any_char: &str = &hello[5..6];
  println!("{:?}",any_char);
}

阴影

fn main() {
  let s: &str = "hello"; // &str
  let s: String = s.to_uppercase(); // String
  println!("{}", s) // HELLO
}

作用

fn say_hello(to_whom: &str) { //type coercion
     println!("Hey {}!", to_whom) 
 }


fn main(){
  let string_slice: &'static str = "you";
  let string: String = string_slice.into(); // &str => String
  say_hello(string_slice);
  say_hello(&string);// &String
 }

连接两个字符串

 // String is at heap, and can be increase or decrease in its size
// The size of &str is fixed.
fn main(){
  let a = "Foo";
  let b = "Bar";
  let c = a + b; //error
  // let c = a.to_string + b;
}

请注意,String和&str是不同的类型,在99%的时间里,您只需要关心&str。

std::字符串只是u8的向量。您可以在源代码中找到它的定义。它是堆分配的,可以生长。

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

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

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

str确实具有可变切片&mut str,例如:pub-fn-split_at_mut(&mut自身,mid:usize)->(&mut字符串,&mut字符串)

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);

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

在Rust中,str是一种表示Unicode标量值序列的原始类型,也称为字符串切片。这意味着它是字符串的只读视图,它不拥有它所指向的内存。另一方面,string是一种可增长的、可变的、拥有的字符串类型。这意味着当您创建字符串时,它将在堆上分配内存以存储字符串的内容,并且当字符串超出范围时,它会释放该内存。因为String是可增长的和可变的,所以您可以在创建String之后更改它的内容。

通常,str在您想要引用存储在另一个数据结构(如string)中的字符串片段时使用。当您想要创建和拥有字符串值时,使用字符串。