rust中的三胞胎姐妹花String,&str和str总是傻傻分不清吗?

343 阅读4分钟

在rust开发过程中我们常常会遇到String, &strstr三个概念,总是朦胧不清,分不清三者之间的关系以及区别,实际开发过程中总是因为分不清三者之间的用法而郁闷苦恼,今天我带你们就详细的探索三者之间的关系,让你不在朦胧不清,而让你豁然开朗。

image.png

  1. str

    • str是一个字符串字面量,它是一个指向有效UTF-8编码的不可变字符串切片的指针。str类型是一个切片类型,它不拥有数据,而是指向数据。
    • 它是&str的别名,通常在模式匹配和函数签名中使用。
    • 用法示例:let s: &str = "Hello, world!";
  2. &str

    • &str是一个字符串切片,它是一个对字符串数据的不可变引用。
    • 它允许你借用字符串数据而不需要拥有所有权,因此可以用于借用字符串字面量或者String类型的数据。
    • 用法示例:let s = String::from("Hello, world!"); let slice: &str = &s;
  3. String

    • String是一个可增长的、可变的字符串类型,它拥有自己的数据。
    • 它是Vec<char>的封装,允许你动态地增加或减少字符串的长度。
    • String是堆分配的,因此它比&str有更多的内存开销,但是提供了更多的灵活性。
    • 用法示例:let mut s = String::new(); s.push_str("Hello, world!");

它们之间的关系和用法如下:

IMG_1062.jpeg

  • 所有权与借用

    • String拥有其数据,而&str则是对数据的引用。
    • 你可以将String传递给函数作为&str,这样函数就可以借用String的数据而不需要拥有它。
  • 可变性

    • String是可变的,你可以改变它的内容。
    • &str是不可变的,你不能改变它指向的数据。
  • 内存分配

    • String在堆上分配内存,允许动态调整大小。
    • &str可以指向堆上的数据(如String)或者栈上的数据(如字符串字面量)。
  • 性能

    • 由于&str不需要堆分配,所以使用&str通常比String更高效,尤其是在性能敏感的场景中。
  • 函数参数

    • 当函数只需要读取字符串内容时,通常使用&str作为参数类型,这样可以避免不必要的数据复制。
    • 当函数需要修改字符串内容时,使用String作为参数类型。

用法示例

String 的用法

String 是一个可增长的、可变的 UTF-8 字符串类型,它拥有自己的数据。

fn main() {
    // 创建一个空的 String
    let mut s = String::new();

    // 使用 push_str 方法追加字符串
    s.push_str("Hello, ");
    s.push_str("world!");

    // 使用 + 运算符和 format! 宏来拼接字符串
    let greeting = format!("{}{}", s, " How are you?");

    // 打印结果
    println!("{}", greeting);
}

str&str 的用法

str 是一个字符串切片,它是一个指向有效 UTF-8 编码序列的不可变引用。

fn main() {
    // 创建一个 String
    let s = String::from("hello world");

    // 通过 & 获取一个 str 的引用
    let slice: &str = &s;

    // 直接使用字符串字面量,它自动被借用为 &str 类型
    let word: &str = "hello";

    // 使用 str 的方法,比如 len()
    println!("Length of slice: {}", slice.len());
    println!("Length of word: {}", word.len());
}

String&str 互相转换的用法

fn main() {
    // 从 &str 创建 String
    let s = String::from("hello world");
    let s_as_str: &str = &s; // 将 String 借用为 &str

    // 从 &str 创建 String
    let str_slice: &str = "I am a string slice";
    let str_from_slice = String::from(str_slice); // 将 &str 转换为 String

    // 打印结果
    println!("String from &str: {}", str_from_slice);
}

&str 作为函数参数的用法

fn main() {
    let my_string = String::from("Rust is fun");

    // 调用函数,传递字符串的引用
    print_first_word(&my_string);

    // 直接传递字符串字面量
    print_first_word("Hello, Rust!");
}

// 函数接受 &str 类型的参数
fn print_first_word(s: &str) {
    let bytes = s.as_bytes();

    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            print!("{}", std::str::from_utf8(&bytes[0..i]).unwrap());
            break;
        }
    }
}

在这个例子中,print_first_word 函数接受一个 &str 类型的参数,这意味着它可以接收任何实现了 Deref trait 的类型,包括 String 和字符串字面量。这样,函数可以处理不同的字符串类型,而不需要关心它们的所有权。

最后如果您也喜欢rust,还请您一键三连,让我有动力持续的输出优质的关于rust的内容,正是因为有了您的支撑,才让我有动力走过这段孤独的路。

扫码_搜索联合传播样式-标准色版.png