Rust 字符串相对于其它语言有点复杂,主要是跟所有权有关。
Rust 字符串涉及两种类型:&str 和 String
1、&str-字面量
str 是 Rust 的内置类型,&str 是 str 的借用。可以理解为字符串字面量。
注意:Rust 字符串不能视为 char 类型的数组。
因为char 类型是 4 字节长度,存储的内容是 Unicode Scalar Value;而Rust 字符串内部默认是使用 utf-8 编码格式的,所以字符串不能视为 char 类型数组,反而更接近 u8 类型的数组。
1.1 O(n) 索引操作
获取字符串的第 i 个元素,可以通过如下方法:
fn main() {
let str = "123";
let first = str.chars().nth(0);
println!("{:?}",first);//Some('1')
}
并不能通过 str[i] 的形式来获取第 i 个元素。str.chars().nth() 的方式时间复杂度为 O(n),因为我们前面说过,Rust 字符串使用 UTF-8 编码,这是一种变长编码格式,我们必须要从头开始遍历一遍,否则不知道第 i 个元素到底在哪。
1.2 内存分配
字符串字面量,在编译时就知道其内容,它的文本内容会直接硬编码到最终的可执行文件里。
由于其不可变性,使得它速度快、高效。
2、String
和 &str 类型相比,String 类型具有管理内存空间的权利。
&str 类型是对一块字符串区间的借用,它对所指向的内存空间没有所有权,即使 mut &str 也是。
比如:
let str : &str = "hello"
我们并没有办法对 str 扩容,在其后面增加内容。但String 类型可以:
fn string_test(){
let mut string = String::from("123");
string.push_str("4");
println!("{}",string);//1234
}
2.1 自动转换&str
由于 String 类型实现了(解引用) Deref[Target=str] ,所以很多情况下,&String 类型可以自动转换成 &str 类型。
//字符串大写转换
fn capitalize(substr : &mut str){
substr.make_ascii_uppercase();
}
fn main() {
let mut s = String::from("Hello World");
capitalize(&mut s);
println!("{}",s)//Hello World
}
capitalize 函数需要的形参是 &mut str,可我们调用的时候传入的参数类型是 &mut String,这里能够编译通过,说明编译器给我们做了自动类型转换。
在 capitalize 函数内部,有权修改 &mut str 所指向的内容,但是无法给这个字符串扩容或者释放内存。