问题历史
在Rust中,有两种主要的字符串类型——&str(字符串切片,不可变,通常是字符串字面量)和String(动态的,可变字符串)。在语言发展的早期阶段,在这两者之间进行选择使得有效内存的处理变得简化,并通过严格的所有权和引用系统确保了处理文本数据时的类型安全。
问题
许多开发者在这两种类型之间的交互中感到困惑。例如,字符串字面量是&'static str,即对在编译阶段分配的不可变字符串的引用,而String可以动态扩展并包含在运行时获取的数据。开发者常常会问如何在类型之间进行转换,如何正确定义所有权并避免多余的拷贝。
解决方案
在理解基本所有权规则的基础上,&str和String之间的转换是透明的:
my_string.as_str())或简单借用(&my_string)从String中获取切片。to_string()或String::from()将&str转换为String。代码示例:
fn main() { let s_literal: &str = "hello"; let s_string: String = String::from(s_literal); let s_slice: &str = &s_string; let new_string = s_slice.to_string(); println!("{} {}", s_string, new_string); }
关键特点:
&str不占用堆内存,始终不可变。String动态分配内存,可以被修改。可以在Rust中修改字符串字面量吗?
不可以,字符串字面量(&'static str)始终是不可变的,任何试图修改字符的行为都会在编译阶段引发错误。
仅仅调用.to_string()在&str上,足以获得可变字符串而不产生多余拷贝吗?
不可以,.to_string()始终会分配新的内存并拷贝内容。这是不可避免的,如果需要基于切片创建可变字符串。
可以在不冒生命期泄漏的风险下从String中获取&str的引用吗?
可以,通过这种方式获取的引用(let s: &str = &my_string;)存活时间不长于原始的String。如果尝试返回一个局部String的&str,会导致生命期错误。
&str的引用保存在临时String中,该字符串超出作用域&str转换为String而没有必要(多余的分配)String::from("text")不会创建数据的副本函数返回一个指向函数内部临时String的&str:
fn faulty() -> &str { let s = String::from("Oops"); &s // 生命期错误! }
优点:
缺点:
函数立即返回一个String并将所有权传递给调用者:
fn correct() -> String { String::from("Safe!") }
优点:
缺点: