文章来源:https://systemxlabs.github.io/blog/rust-slice/
切片定义
切片是一种动态大小类型,表示 T 类型元素序列的“视图”。切片类型被写作 [T]
。
切片主要通过指针类型来使用
&[T]
:共享切片,经常被直接称作切片(对指向数据的不可变借用)&mut [T]
:可变切片(对指向数据的可变借用)Box<[T]>
:boxed 切片,拥有其所有权
切片 [T]
与数组 [T; N]
比较
- 类型:
[T]
是切片类型;[T; N]
是数组类型,且[T; 2]
和[T; 3]
是不同的数组类型 - 编译期大小:
[T]
是编译期未知大小(DST),而[T; N]
是编译期已知大小的 - 容量均不可变:
[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 字符的边界。
其他
- 数组和字符串的许多方法(如遍历、搜索、排序等)是在切片上定义的
- 通常优先使用切片类型
&[T]
/&str
,因为使用&Vec<T>
/&String
会多一层跳转到Vec<T>
/String
再调用其方法
1
共 7 条评论, 1 页
评论区
写评论感觉你的理解有点混乱。
--
👇
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 类型的变量(即引用)通常存储在栈上,但它们引用的数据可以位于栈上或堆上。
&str才是引用,还有字符串字面量怎么存储在栈上,它是存储在程序二进制.rodata段内
你指的是&str,它是栈上的数据,是一个双字的胖指针。str是DST类型,是不能直接放在栈上
在 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 类型的变量(即引用)通常存储在栈上,但它们引用的数据可以位于栈上或堆上。
Box<str>
类型才是将指针放置到堆上,单纯的str只是栈上的数据,这个数据是指针和len长度,并没有真实的String buf 数据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则是更好的选择。
"str 不仅指存放在程序只读区域的字面量,也可以指存放在堆上的字符串。"这句话有问题,str是字符串切片,他指的是栈上的数据,并且不能扩容,不能改变等等,如果是堆上的数据,那肯定可以自由扩容了。str可以从String类型创建而来,他的底层数据确实是String类型,但是不代表他俩是一个东西