字符串切片
切片(Slice)
是一种没有所有权的数据类型。 切片引用连续的内存分配而不是整个集合。 它允许安全,高效地访问数组而无需复制。 切片不是直接创建的,而是从现有变量创建的。 切片由长度组成,并且可以是可变的或不可变的。 切片的行为与数组相同。
字符串slice(string slice)
是 String
中一部分值的引用
,它看起来像这样:
fn main() {
let s = String::from("hello world");
let hello = &s[0..5];
let world = &s[6..11];
}
不同于整个String
的引用,hello
是一个部分 String
的引用,由一个额外的 [0..5]
部分指定。可以使用一个由中括号中的 [starting_index..ending_index]
指定的 range
创建一个 slice
,其中 starting_index
是 slice
的第一个位置,ending_index
则是 slice
最后一个位置的后一个值。在其内部,slice
的数据结构存储了 slice
的开始位置和长度,长度对应于 ending_index
减去 starting_index
的值。所以对于 let world = &s[6..11];
的情况,world
将是一个包含指向 s
索引 6
的指针和长度值5
的 slice
。
对于 Rust
的 .. range
语法,如果想要从索引 0
开始,可以不写两个点号之前的值。换句话说,如下两个语句是相同的:
let s = String::from("hello");
let slice = &s[0..2];
let slice = &s[..2];
依此类推,如果 slice
包含 String
的最后一个字节,也可以舍弃尾部的数字。这意味着如下也是相同的:
let s = String::from("hello");
let slice = &s[3..s.len()];
let slice = &s[3..];
也可以同时舍弃这两个值来获取整个字符串的 slice
。所以如下亦是相同的:
let s = String::from("hello");
let slice = &s[0..s.len()];
let slice = &s[..];
如果有一个字符串切片,那么可以直接传递它作为参数。将字符串切片作为参数传递给函数,而不是传递引用,以使API更通用和有用,而不会失去其功能。
fn main() {
let mut a = String::from("hello world");
first_word(&a[5..]);
//手动清除 a
a.clear();
}
fn first_word(s: &str) {
println!("{}", s);
}
slice
是 String
中一部分值的引用
,看例子:
fn main() {
let mut a = String::from("hello world");
let b = second_word(&a);
//手动清除 a
a.clear();
println!("b is: {}", b);
}
fn second_word(s: &String) -> &str {
return &s[5..];
}
这里是编译错误:
$ cargo run
Compiling variables v0.1.0 (/rust/projects/variables)
error[E0502]: cannot borrow `a` as mutable because it is also borrowed as immutable
--> src/main.rs:7:5
|
4 | let b = second_word(&a);
| -- immutable borrow occurs here
...
7 | a.clear();
| ^^^^^^^^^ mutable borrow occurs here
8 |
9 | println!("b is: {}", b);
| - immutable borrow later used here
For more information about this error, try `rustc --explain E0502`.
error: could not compile `variables` due to previous error
回忆一下借用规则,当拥有某值的不可变引用时,就不能再获取一个可变引用。因为 clear
需要清空 String
,它尝试获取一个可变引用。在调用 clear
之后的 println!
使用了 b
中的引用,所以这个不可变的引用在此时必须仍然有效。Rust
不允许 clear
中的可变引用和 b
中的不可变引用同时存在,因此编译失败。
字符串 slice
,正如你想象的那样,是针对字符串的。不过也有更通用的 slice
类型。考虑一下这个数组:
let a = [1, 2, 3, 4, 5];
就跟我们想要获取字符串的一部分那样,我们也会想要引用数组的一部分。我们可以这样做:
let a = [1, 2, 3, 4, 5];
let slice = &a[1..3];
assert_eq!(slice, &[2, 3]);
这个 slice
的类型是 &[i32]
。它跟字符串 slice
的工作方式一样,通过存储第一个集合元素的引用和一个集合总长度。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!