问题背景:
与原生语言(C/C++)相比,Rust通过严格区分引用类型(&str)和拥有类型(String)来构建安全的字符串处理。这消除了大多数与内存管理、缓冲区溢出及双重释放相关的错误。
问题:
与成年GC语言不同,在这些语言中,任何字符串都存在于受管理的内存中,Rust需要明确知道谁拥有字符串,它存在多长时间,以及如何在修改后避免悬挂引用。处理UTF-8字符串时,在索引和修改时需要特别小心。
解决方案:
在Rust中,String是一种可变的、堆分配的字符串,拥有自己的内容。&str是对字节序列的不可变引用,并具有UTF-8的保证。如有必要,可以通过标准库的方法安全地进行转换(&str -> String及反之亦然)。
代码示例:
fn main() { let owned: String = String::from("Rust"); let borrowed: &str = &owned; let primitive: &str = "Hello"; // 文本字面量总是&str // 转换 &str -> String let s: String = primitive.to_string(); // 转换 String -> &str let st: &str = &s; println!("{} {} {} {}", owned, borrowed, primitive, st); }
关键特性:
&'static str,而非String为什么不能像s[1]或s[i]那样索引字符串?
Rust中的字符串是UTF-8的,因此无法直接索引:s[i]不会返回第i个字符,有时会在访问不正确的字节边界时导致panic。请使用方法.chars().nth(i)或.get(start..end)。
可以安全地修改&str吗?
不可以——&str始终是不可变切片。要进行修改,请使用to_owned/to_string,或使用String/Vec<u8>。
String::from("abc")与"abc".to_string()有什么根本区别?
这两种方式的结果是等价的,都是通过复制数据从&str创建String。不同之处仅在于风格:例如,to_string是通过Trait ToString实现的,而String::from更清晰地表达了“创建所有权”的意图。
函数接受String并在内部进行不必要的字符串复制(clone),然后将切片写入其他函数,忘记延长来源的生命周期。结果:悬挂引用&崩溃。
优点:
缺点:
函数接受&str,如果需要修改,则在内部调用.to_string(),外部逻辑保持“零复制”。生命周期得到控制,没有多余的分配。
优点:
缺点: