< 返回版块

lewiszlw 发表于 2024-03-25 22:22

Tags:rust, slice

文章来源:https://systemxlabs.github.io/blog/rust-slice/

切片定义

切片是一种动态大小类型,表示 T 类型元素序列的“视图”。切片类型被写作 [T]

切片主要通过指针类型来使用

  • &[T]:共享切片,经常被直接称作切片(对指向数据的不可变借用)
  • &mut [T]:可变切片(对指向数据的可变借用)
  • Box<[T]>:boxed 切片,拥有其所有权

rust-container-cheat-sheet

切片 [T] 与数组 [T; N] 比较

  1. 类型:[T] 是切片类型;[T; N] 是数组类型,且 [T; 2][T; 3] 是不同的数组类型
  2. 编译期大小:[T] 是编译期未知大小(DST),而 [T; N] 是编译期已知大小的
  3. 容量均不可变: [T][T; N] 可以改变元素内容,但容量不可变

切片引用 &[T] / &mut [T] 与普通引用 &T 的区别

切片引用是一个双字值的胖指针,包含指针和长度;而普通引用只包含指针。

let pointer_size = std::mem::size_of::<&u8>();
assert_eq!(pointer_size, std::mem::size_of::<&String>());
assert_eq!(2 * pointer_size, std::mem::size_of::<&str>());
assert_eq!(2 * pointer_size, std::mem::size_of::<&[u8]>());
assert_eq!(2 * pointer_size, std::mem::size_of::<*const [u8]>());
assert_eq!(2 * pointer_size, std::mem::size_of::<Box<[u8]>>());
assert_eq!(2 * pointer_size, std::mem::size_of::<Rc<[u8]>>());

字符串切片 str

str 类似 [u8] ,只不过 str 需要保证里面的字节内容是 UTF-8 编码的。

str 不仅指存放在程序只读区域的字面量,也可以指存放在堆上的字符串。

let s: &str = "hello";
let s: String = String::from(s);
let s: Box<str> = s.into_boxed_str();

在对字符串使用切片语法时需要格外小心,切片的索引必须落在字符之间的边界位置,也就是 UTF-8 字符的边界。

其他

  1. 数组和字符串的许多方法(如遍历、搜索、排序等)是在切片上定义的
  2. 通常优先使用切片类型 &[T] / &str,因为使用 &Vec<T> / &String 会多一层跳转到 Vec<T> / String 再调用其方法

评论区

写评论
作者 lewiszlw 2024-03-27 15:07

感觉你的理解有点混乱。

--
👇
AnkoGo123: 在 Rust 中,str 类型的数据并不是直接存储在堆上或栈上,而是取决于它如何被使用。str 是一个对字符数据的引用,可以是栈上的字面量字符串,也可以是堆上分配的 String 类型的一部分。

栈上存储:

当 str 是一个字面量字符串时,它通常存储在程序的只读数据段中,这是栈的一部分。例如:

rust let s: &str = "hello";

在这个例子中,"hello" 是一个字面量字符串,它存储在栈上。变量 s 是一个对这个字符串的引用,也存储在栈上。

堆上存储:

当 str 是 String 的一部分时,String 本身存储在堆上,而 str 是对 String 内部缓冲区的引用。例如:

rust let s = String::from("hello"); let ref_to_s: &str = &s;

在这个例子中,s 是一个 String,它存储在堆上。ref_to_s 是一个对 s 内部数据的引用(即 str),这个引用通常也会存储在栈上。但是,ref_to_s 引用的实际数据(即字符串 "hello")是在 String 的堆上分配的内存中。

总结来说,str 类型本身不直接存储数据,而是引用其他位置的数据。这些数据可以是栈上的字面量字符串,也可以是堆上 String 类型的内部缓冲区。str 类型的变量(即引用)通常存储在栈上,但它们引用的数据可以位于栈上或堆上。

作者 lewiszlw 2024-03-27 15:06

在 Rust 中,str 类型的数据并不是直接存储在堆上或栈上,而是取决于它如何被使用。str 是一个对字符数 据的引用,可以是栈上的字面量字符串,也可以是堆上分配的 String 类型的一部分。

&str才是引用,还有字符串字面量怎么存储在栈上,它是存储在程序二进制.rodata段内

作者 lewiszlw 2024-03-27 14:56

单纯的str只是栈上的数据,这个数据是指针和len长度,并没有真实的String buf 数据

你指的是&str,它是栈上的数据,是一个双字的胖指针。str是DST类型,是不能直接放在栈上

ankoGo 2024-03-26 13:10

在 Rust 中,str 类型的数据并不是直接存储在堆上或栈上,而是取决于它如何被使用。str 是一个对字符数据的引用,可以是栈上的字面量字符串,也可以是堆上分配的 String 类型的一部分。

栈上存储:

当 str 是一个字面量字符串时,它通常存储在程序的只读数据段中,这是栈的一部分。例如:

rust let s: &str = "hello";

在这个例子中,"hello" 是一个字面量字符串,它存储在栈上。变量 s 是一个对这个字符串的引用,也存储在栈上。

堆上存储:

当 str 是 String 的一部分时,String 本身存储在堆上,而 str 是对 String 内部缓冲区的引用。例如:

rust let s = String::from("hello"); let ref_to_s: &str = &s;

在这个例子中,s 是一个 String,它存储在堆上。ref_to_s 是一个对 s 内部数据的引用(即 str),这个引用通常也会存储在栈上。但是,ref_to_s 引用的实际数据(即字符串 "hello")是在 String 的堆上分配的内存中。

总结来说,str 类型本身不直接存储数据,而是引用其他位置的数据。这些数据可以是栈上的字面量字符串,也可以是堆上 String 类型的内部缓冲区。str 类型的变量(即引用)通常存储在栈上,但它们引用的数据可以位于栈上或堆上。

ankoGo 2024-03-26 12:58

Box<str>类型才是将指针放置到堆上,单纯的str只是栈上的数据,这个数据是指针和len长度,并没有真实的String buf 数据

ankoGo 2024-03-26 12:51

rust str和String类型区别:

来自百度AI的回复: Rust中的str和String类型都是用于处理字符串的,但它们之间存在一些重要的区别。

所有权和生命周期:

str是一个原始指针,它指向一个UTF-8编码的字节序列。它通常是由&str(一个指向字符串切片的引用)来表示的,这意味着它并没有自己的内存分配,而是指向某个已经存在的内存区域。因此,str的生命周期是与其所指向的数据相关联的。 String则是一个拥有自己内存分配的类型,它包含了一个堆上分配的UTF-8编码的字节序列以及一个指向该字节序列的原始指针。由于String拥有其数据的所有权,所以它的生命周期是独立的。 不可变性和可变性:

str是不可变的,这意味着你不能修改一个已经存在的str。 String是可变的,你可以使用mut关键字来修改一个String。 性能:

由于str只是一个引用,所以对其进行操作(如连接、切片等)通常是非常便宜的,因为它们只是指针操作。 String的操作可能会涉及堆分配和内存复制,所以相对来说可能更昂贵。 用途:

str通常用于表示字符串切片,这些切片可能是从其他字符串、文件、网络等地方获取的。 String通常用于当你需要一个可以修改的字符串时,或者当你需要创建一个新的、独立的字符串时。 转换:

你可以从&str转换为String,但这通常涉及堆分配和复制操作。 从String转换为&str是便宜的,因为你只是获取一个指向数据的引用。 总的来说,str和String在Rust中各有其用途,选择使用哪一个取决于你的具体需求。对于大多数情况,使用&str(字符串切片)是更好的选择,因为它们更轻量级且更安全。但是,当你需要修改字符串或创建新的独立字符串时,String则是更好的选择。

ankoGo 2024-03-26 12:48

"str 不仅指存放在程序只读区域的字面量,也可以指存放在堆上的字符串。"这句话有问题,str是字符串切片,他指的是栈上的数据,并且不能扩容,不能改变等等,如果是堆上的数据,那肯定可以自由扩容了。str可以从String类型创建而来,他的底层数据确实是String类型,但是不代表他俩是一个东西

1 共 7 条评论, 1 页