基础篇-Slice(切片)

  • 木头
  • 更新于 2023-02-20 15:15
  • 阅读 1937

字符串切片

切片(Slice)是一种没有所有权的数据类型。 切片引用连续的内存分配而不是整个集合。 它允许安全,高效地访问数组而无需复制。 切片不是直接创建的,而是从现有变量创建的。 切片由长度组成,并且可以是可变的或不可变的。 切片的行为与数组相同。

字符串 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_indexslice 的第一个位置,ending_index 则是 slice 最后一个位置的后一个值。在其内部,slice的数据结构存储了 slice 的开始位置和长度,长度对应于 ending_index 减去 starting_index 的值。所以对于 let world = &s[6..11]; 的情况,world 将是一个包含指向 s 索引 6的指针和长度值5sliceimage.png

对于 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);
}

字符串切片作为返回值

sliceString 中一部分值的引用,看例子:

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,正如你想象的那样,是针对字符串的。不过也有更通用的 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 的工作方式一样,通过存储第一个集合元素的引用和一个集合总长度。

  • 原创
  • 学分: 6
  • 分类: Rust
  • 标签:
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。
125 订阅 31 篇文章

0 条评论

请先 登录 后评论
木头
木头
0xC020...10cf
江湖只有他的大名,没有他的介绍。