Skip to content

Slice 类型

slice 允许你引用集合中一段连续的元素序列, 而不用引用整个集合, slice 是一种引用, 所以它没有所有权

用c语言操作内存模拟实现 Rust 切片, 从而看清 Slice(切片) 的本质:

c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 定义一个结构体来模拟 Rust 的切片
typedef struct Slice {
  char *source_data_ptr; // 保存原数据内存地址的指针(切片的开始位置)
  size_t length;         // 切片数据的长度
} Slice;

// 创建源数据内容, 创建一个字符串切片
Slice create_slice(char *array, size_t start, size_t end) {
  Slice slice = {
      .source_data_ptr = array + start,
      .length = end - start,
  };
  return slice;
}

// 打印切片的内容
void print_slice(const Slice *slice) {
  for (int i = 0; i < slice->length; i++) {
    printf("index:%d, value:%c \n", i, slice->source_data_ptr[i]);
  }
}

int main() {
  // 创建一个字符串, 存放到堆中, 模拟不确定字符串长度的情况
  int str_len = 11;
  char *str = (char *)malloc(sizeof(char) * str_len + 1); // +1:最后有个 \0 字符
  if (str == NULL) {
    fprintf(stderr, "Memory allocation failed at %s:%d\n", __FILE__, __LINE__);
    return 1;
  }
  strcpy(str, "hello world");

  // 创建一个切片, 从索引 6 开始到 11 结束
  // 为什么切片没有所有权, 因为它存的不是原字符串, 而是
  // "部分字符串的描述": 源数据的内存地址(切片开始位置), 切片数据长度
  // 获取的时候, 根据切片的描述去源数据中获取
  Slice slice = create_slice(str, 6, str_len);

  // 打印切片的内容
  print_slice(&slice); // world

  // 最后释放原字符串的内存
  free(str);
  str = NULL;

  return 0;
}

slice

字符串 slice

rust
fn main() {
    let string = String::from("hello world");
    let str = &string[6..11]; // 表示 6-11

    // 这个语法中的开始和结尾是可以省略的
    let str1 = &string[...5]; // 表示 0-5
    let str2 = &string[6...]; // 表示 6 到最后
    let str3 = &stirng[..];   // 表示最前到最后

    println!("str: {str}");
    println!("str1: {str1}");
    println!("str2: {str2}");
    println!("str3: {str3}");
}

字符串字面值就是 slice

rust
fn main() {
    // 注意这俩的区别
    let str: &str = "hello";
    let string: String = String::from("world");
    println!("str: {str}");
    println!("string: {string}");
}

slice 作为函数参数和返回值

rust
fn first_world(str: &str) -> &str {
    // 将字符串/切片转字符数组 ['h', 'e', 'l', 'l', 'o']
    let bytes = str.as_bytes();

    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return &str[0..i];
        }
    }
    // &str[..] 可能会有警告, 所以建议修改为这样
    &str[0..bytes.len()]
}

fn main() {
    let str = String::from("hello world");

    // &str 是 &String, 但是可以看做 &str[..]
    // 这样就可以同时兼容 &String 和 &str 类型
    let sub_str = first_world(&str);
    println!("sub_str: {sub_str}");
}

其他类型的slice

rust
fn main() {
    let arr = [1,2,3,4,5];
    let sub_arr = &arr[0..3];

    let mut i = 0;
    while i < sub_arr.len() {
        println!("i={}", sub_arr[i]);
        i += 1;
    }
}

Released under the MIT License.