5分钟速读之Rust权威指南(十三)

297 阅读3分钟

通用集合类型-字符串String

本节介绍之前就认识的一个数据集合:String,也就是就是字符char的集合,rust在语言核心部分只有一种字符串类型,那就是字符串切片str,它通常以借用的形式出现,也就是&str。当我们提到“字符串”时,他们通常指的是String和字符串切片&str这两种类型。另外,字符串都是基于UTF-8编码的。

创建一个字符串

许多对于Vec可用的操作也同样可用于String,我们可以从new函数开始来创建一个字符串:

// 创建一个空字符串
let s = String::new()

// 使用字面量&str切片转换成字符串类型
let s2 = "hello".to_string()

// 还可以使用from方法:
let s3 = String::from("hello")

更新字符串

使用push_str或push向字符串中添加内容:

let mut s = String::from("hello");

// push_str用于追加字符串
s.push_str(" world");
println!("{}", s); // hello world

// push用于追加单个字符char
s.push('!');
println!("{}", s); // hello world!

为什么字符串切片是以引用的方式出现?为了方便再次使用:

let mut s = String::from("hello");

// s2的类型是&str
let s2 = " world";

// 这里不会拿走s2的所有权,因为s2是引用类型
s.push_str(s2);

println!("{}", s);
// "hello, world"

// 如果s2的类型不是引用形式,
// s.push_str(s2)将拿走s2的所有权
// s2将不能再被使用
println!("{}", s2);
// " world"

拼接字符串有一个限制,第一个字符串需要是String类型,后面的都是&str类型:

let s = String::from("hello");
let s2 = String::from(", world");
let s3 = "!";

// 以s开头,将字符串拼接
let s4 = s + &s2 + &s3;

// 获取拼接结果
println!("{}", s4); // "hello, world!"

// 获取被拼接的s2和s3
println!("{}", s2); // , world
println!("{}", s3); // !

// 由于上面字符串拼接过程中开头的s是具有所有权的字符串,
// 拼接之后所有权转移给了s4
println!("{}", s); // 报错,没有了所有权,不再可用

字符串还可以使用format!宏来拼接:

let s = String::from("hello");
let s2 = String::from(", world");
let s3 = "!";

// format!的用法类似于println!
// 这种方式不会获取任何一个字符串的所有权
let s4 = format!("{}{}{}",s, s2, s3);

// 所有字符串都可用
println!("{}", s4); // hello, world!
println!("{}", s); // hello
println!("{}", s2); // , world
println!("{}", s3); // !

字符串索引

在JS中,可以使用索引来访问字符串,但是在rust中是不支持的:

let s = "hello";
let h = s[0]; // 报错,字符串不支持索引

// 因为有些字符的Unicode标量值占用两个字符,
// 当我们按照索引访问时,可能访问了字符的一半,
// 不是一个合法字符,所以rust不允许这么做
let s2 = "🍔";
let s3 = "a";
println!("{}", s2.len()); // 4
println!("{}", s3.len()); // 1

字符串切片

通过切片实现类似索引的效果:

let s = "🍔";
let s2 = &s[0..1]; // 报错, 非法字符
let s3 = &s[0..4]; // 🍔

遍历字符串

使用chars方法进行遍历,过程中rust可以按照Unicode识别完整的字符:

let s = "hello, world🍔";
for c in s.chars() {
  println!("{}", c);
  // 依次输出:hello, world🍔
}

使用bytes方法可以依次返回每个原始字节:

let s22 = "🍔";
for b in s22.bytes() {
  println!("{}", b);
  // 依次输出:240 159 141 148
}