Slice
另一个没有所有权的数据类型是 slice。slice 允许你引用集合中一段连续的元素序列,而不用引用整个集合。
let mut s = String::from("hello world");
let l = first_world(&s);
s.clear(); // 清空字符串, s = ”“
println!("s = {}", s);
println!("word = {}", l);
// l 在此处的值仍然是 5,
// 但是没有更多的字符串让我们可以有效地应用数值 l 的值现在完全无效!
fn first_world(s: &String) -> usize {
let bytes = s.as_bytes();
// iter 方法返回集合中的每一个元素,而 enumerate 包装了 iter 的结果,将这些元素作为元组的一部分来返回
for (i, &item) in bytes.iter().enumerate() {
if item == b' ' {
return i;
}
}
s.len()
}
字符串 slice(string slice)是 String 中一部分值的引用,它看起来像这样:
let s = String::from("hello world");
// 引用整个 String 不过带有额外的 [0..5] 部分。它不是对整个 String 的引用,而是对部分 String 的引用。
let hello = &s[0..5];
let world = &s[6..11];
println!("{} {}", hello, world);
从 0 开始的 slice , 简单写法
let s = String::from("apple");
let s1 = &s[0..2];
let s2 = &s[..2];
println!("s1 = {}, s2 = {}", s1, s2);
以字符串结尾为结尾的 slice , 简单写法
let s = String::from("apple");
let len = s.len();
let s1 = &s[2..len];
let s2 = &s[2..];
println!("s1 = {}, s2 = {}", s1, s2);
获取整个字符串的简单写法
let s = String::from("apple");
let len = s.len();
let s1 = &s[0..len];
let s2 = &s[..];
println!("s1 = {}, s2 = {}", s1, s2);
Slice string 的引用
let s = String::from("hello apple");
let first = first_world1(&s);
// s.clear(); // s 被引用, 不能清除
println!("first = {}", first);
fn first_world1(s: &String) -> &str {
let bytes = s.as_bytes();
for (i, &item) in bytes.iter().enumerate() {
if item == b' ' {
return &s[0..i];
}
}
&s[..]
}
字符串字面值就是 slice
let s = "Hello, world!";
println!("s = {}", s);
// 这里 s 的类型是 &str:它是一个指向二进制程序特定位置的 slice。这也就是为什么字符串字面值是不可变的;&str 是一个不可变引用。
字符串 slice 作为参数
改进写法 1
let s = String::from("hello world");
let first = first_world2(&s[..]);
println!("first = {}", first);
改进写法2
let s = "hello world";
// 传入 slice
let first = first_world2(&s[..]);
println!("first = {}", first);
// 因为字面量,其本身也是 slice, 所以也可以直接传入
let first = first_world2(s);
println!("first = {}", first);
fn first_world2(s: &str) -> &str {
let bytes = s.as_bytes();
for (i, &item) in bytes.iter().enumerate() {
if item == b' ' {
return &s[0..i];
}
}
&s[..]
}
其他类型的 slice
let a = [1, 2, 3, 4, 5];
let s = &a[0..3];
println!("s = {:?}", s);
所有权、借用和 slice 这些概念让 Rust 程序在编译时确保内存安全。Rust 语言提供了跟其他系统编程语言相同的方式来控制你使用的内存,但拥有数据所有者在离开作用域后自动清除其数据的功能意味着你无须额外编写和调试相关的控制代码。