返回介绍

7.3 切片

发布于 2024-10-13 11:25:29 字数 3531 浏览 0 评论 0 收藏 0

切片(slice, [T] )引用序列对象片段,无所有权。动态尺寸类型(DST, dynamically sized type),只能以 &[T] 存储或传递。

A type with a size that is known only at runtime is called a dynamically sized type (DST) or, informally, an unsized type. Slices and trait objects are two examples of DSTs.

let v = [1, 2, 3];
let s = v[..];
  ^ doesn't have a size known at compile-time
    note: all local variables must have a statically known size

数组 [T; len] vs &[T] 切片,因为 [T] 长度在编译期无法确认,所以只能通过固定长度的 指针 定义。所谓 &[T] ,是固定长度结构体的胖指针,存储指针和长度信息。

数据结构示意图:

   &[T]        
  +=====+       +=======//=======+
  | ptr | ----------> | data ...     |
  +-----+       +=======//=======+
  | len |
  +=====+
  
struct &[T] {
  data_ptr: *mut T,
  length  : usize,
}

切片类型:

  • &[T] : shared slice。
  • &mut [T] : mutable slice。
  • Box<[T]> : owned slice。

构造

从已有序列对象,以起始和结束索引进行构造。

  • [..] : [0, len - 1]
  • [0..2] : [0, 2)
  • [0..=2] : [0, 2]
  • [3..] : [3, len - 1]
  • [..3] : [0, 3)
  • [..=3] : [0, 3]

&v[..] 的实际操作是 &(v[..])

fn main() {
  let v = vec![0, 1, 2, 3];

  let s = &v[..];        // [0, 3]
  assert_eq!([0, 1, 2, 3], s);

  let s = &v[0..2];        // [0, 2)
  assert_eq!([0, 1], s);

  let s = &v[0..=2];       // [0, 2]
  assert_eq!([0, 1, 2], s);

  let s = &v[..2];         // [0, 2)
  assert_eq!([0, 1], s);

  let s = &v[..=2];        // [0, 2]
  assert_eq!([0, 1, 2], s);

  let s = &v[2..];         // [2, 3]
  assert_eq!([2, 3], s);
}

注意区别数组引用和切片,虽然可以强制转换。

use std::convert::TryFrom;

fn type_of<T>(_: &T) -> &'static str {
  std::any::type_name::<T>()
}

fn main() {
  let a = &[1, 2, 3];
  let s = &a[..];

  assert_eq!(type_of(&a), "&[i32; 3]");  // &array
  assert_eq!(type_of(&s), "&[i32]");   // &slice

  // --- convert -------

  let s2: &[i32] = &[1, 2, 3];          // array -> slice
  let a2 = <&[i32; 3]>::try_from(s2).unwrap();  // slice -> array

  assert_eq!(type_of(&s),  "&[i32]"); 
  assert_eq!(type_of(&a2), "&[i32; 3]");
  
  println!("{:?}", a2);        // [1, 2, 3]
}

操作

通过可变切片间接修改源数据。注意,切片索引与源数据索引未必一致。

fn main() {
  let mut v = vec![0, 1, 2, 3];
  
  let s = &mut v[2..];
  s[0] += 100;

  assert_eq!(v, [0, 1, 102, 3]);
}

遍历(修改)切片。

fn main() {
  let s = &mut [1, 2, 3][..];

  for x in s.iter_mut() {
    *x += 100;
  }

  for x in s.iter() {
    println!("{:?}", x);
  }

  println!("{:?}", s);
}

可对切片进行重切(reslice)操作。

fn main() {
  let mut a = [1, 2, 3];

  let s = &mut a[..];
  let s2 = &mut s[1..];

  s2[1] += 100;
  
  println!("{:?}", s);
  println!("{:?}", a);
}

重新切片受目标切片限制,而非其底层数组。

fn main() {
  let mut a = [1, 2, 3, 4, 5, 6];

  let s  = &mut a[..3];
  let s2 = &mut s[1..4];
          ^ range end index 4 out of range for slice of length 3
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文