Rust里有切片(slice),切片是对多个连续元素的引用。
你可以借用一个vector的切片,例如:
fn main() {
let v = vec![1, 2, 3, 4, 5];
let v2 = &v[2..4];
println!("v2 = {:?}", v2);
}
// output:
// v2 = [3, 4]
复制代码
上面不是魔法。索引操作符(foo[index])被Index和IndexMut两个traits重载。
..语法只是range字面量。Ranges是定义在标准库的一些结构体。
它们可以是开放-闭合的,如果想要包含最右边的元素,可以使用=来处理:
fn main() {
// 0 or greater
println!("{:?}", (0..).contains(&100)); // true
// strictly less than 20
println!("{:?}", (..20).contains(&20)); // false
// 20 or less than 20
println!("{:?}", (..=20).contains(&20)); // true
// only 3, 4, 5
println!("{:?}", (3..6).contains(&4)); // true
}
复制代码
借用规则也适用于切片(slice):
fn tail(s: &[u8]) -> &[u8] {
&s[1..]
}
fn main() {
let x = &[1, 2, 3, 4, 5];
let y = tail(x);
println!("y = {:?}", y);
}
复制代码
上面的代码和下面是一样的:
fn tail(s: &'a [u8]) -> &'a [u8] {
&s[1..]
}
复制代码
这样子写也是合法的:
fn main() {
let y = {
let x = &[1, 2, 3, 4, 5];
tail(x)
};
println!("y = {:?}", y);
}
复制代码
但是上面的代码合法只是因为[1,2,3,4,5]是一个'static'数组。所以下面的代码是不合法的:
fn main() {
let y = {
let v = vec![1, 2, 3, 4, 5];
tail(&v)
// error: `v` does not live long enough
};
println!("y = {:?}", y);
}
复制代码
因为一个vector是分配在堆上的,它的生命周期是不是'static'。
&str类型的值是真正的切片。
fn file_ext(name: &str) -> Option {
// this does not create a new string - it returns
// a slice of the argument.
name.split(".").last()
}
fn main() {
let name = "Read me. Or don't.txt";
if let Some(ext) = file_ext(name) {
println!("file extension: {}", ext);
} else {
println!("no file extension");
}
}
复制代码
所以借用规则也适用于这里:
fn main() {
let ext = {
let name = String::from("Read me. Or don't.txt");
file_ext(&name).unwrap_or("")
// error: `name` does not live long enough
};
println!("extension: {:?}", ext);
}
复制代码
调用失败,函数典型情况下会返回一个Result:
fn main() {
let s = std::str::from_utf8(&[240, 159, 141, 137]);
println!("{:?}", s);
// prints: Ok("🍉")
let s = std::str::from_utf8(&[195, 40]);
println!("{:?}", s);
// prints: Err(Utf8Error { valid_up_to: 0, error_len: Some(1) })
}
复制代码
如果你想在失败的时候直接panic,你可以使用unwrap():
fn main() {
let s = std::str::from_utf8(&[240, 159, 141, 137]).unwrap();
println!("{:?}", s);
// prints: "🍉"
let s = std::str::from_utf8(&[195, 40]).unwrap();
// prints: thread 'main' panicked at 'called `Result::unwrap()`
// on an `Err` value: Utf8Error { valid_up_to: 0, error_len: Some(1) }',
// src/libcore/result.rs:1165:5
}
复制代码
或者,如果想要输出自定义信息的话可以使用.expect():
fn main() {
let s = std::str::from_utf8(&[195, 40]).expect("valid utf-8");
// prints: thread 'main' panicked at 'valid utf-8: Utf8Error
// { valid_up_to: 0, error_len: Some(1) }', src/libcore/result.rs:1165:5
}
复制代码
或者你可以使用match:
fn main() {
match std::str::from_utf8(&[240, 159, 141, 137]) {
Ok(s) => println!("{}", s),
Err(e) => panic!(e),
}
// prints 🍉
}
复制代码
或者你可以使用if let:
fn main() {
if let Ok(s) = std::str::from_utf8(&[240, 159, 141, 137]) {
println!("{}", s);
}
// prints 🍉
}
复制代码
或者你可以把错误抛到上一层:
fn main() -> Result {
match std::str::from_utf8(&[240, 159, 141, 137]) {
Ok(s) => println!("{}", s),
Err(e) => return Err(e),
}
Ok(())
}
复制代码
或者你可以使用一种更简洁的操作?:
fn main() -> Result {
let s = std::str::from_utf8(&[240, 159, 141, 137])?;
println!("{}", s);
Ok(())
}
复制代码
*操作符可以用于解引用,但是在访问内部字段或者调用方法的时候可以不进行解引用操作:
struct Point {
x: f64,
y: f64,
}
fn main() {
let p = Point { x: 1.0, y: 3.0 };
let p_ref = &p;
println!("({}, {})", p_ref.x, p_ref.y);
}
// prints `(1, 3)`
复制代码
并且解引用操作只能在实现了Copytrait的类型上使用:
struct Point {
x: f64,
y: f64,
}
fn negate(p: Point) -> Point {
Point {
x: -p.x,
y: -p.y,
}
}
fn main() {
let p = Point { x: 1.0, y: 3.0 };
let p_ref = &p;
negate(*p_ref);
// error: cannot move out of `*p_ref` which is behind a shared reference
}
复制代码// now `Point` is `Copy`
#[derive(Clone, Copy)]
struct Point {
x: f64,
y: f64,
}
fn negate(p: Point) -> Point {
Point {
x: -p.x,
y: -p.y,
}
}
fn main() {
let p = Point { x: 1.0, y: 3.0 };
let p_ref = &p;
negate(*p_ref); // ...and now this works
}
复制代码
原文链接
欢迎关注我的微信公众号: