跳转至

4 关键字

1 unsafe

  • 参考 https://rustwiki.org/zh-CN/std/keyword.unsafe.html

2 ref

ref 也是一种引用,可以用来替代 & 修饰变量,语法上在等号的左边,表示此变量是引用其它变量;也可用来创建结构体/元组的字段的引用。

#[derive(Clone, Copy)]
struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let c = 'Q';
    // 赋值语句中左边的 `ref` 关键字等价于右边的 `&` 符号。
    let ref ref_c1 = c;
    let ref_c2 = &c;
    println!("ref_c1 equals ref_c2: {}", *ref_c1 == *ref_c2);
    let point = Point { x: 0, y: 0 };
    // 在解构一个结构体时 `ref` 同样有效。
    let _copy_of_x = {
        // `ref_to_x` 是一个指向 `point` 的 `x` 字段的引用。
        let Point {
            x: ref ref_to_x,
            y: _,
        } = point;
        // 返回一个 `point` 的 `x` 字段的拷贝。
        *ref_to_x
    };
    // `point` 的可变拷贝
    let mut mutable_point = point;
    {
        // `ref` 可以与 `mut` 结合以创建可变引用。
        let Point {
            x: _,
            y: ref mut mut_ref_to_y,
        } = mutable_point;
        // 通过可变引用来改变 `mutable_point` 的字段 `y`。
        *mut_ref_to_y = 1;
    }
    println!("point is ({}, {})", point.x, point.y);
    println!(
        "mutable_point is ({}, {})",
        mutable_point.x, mutable_point.y
    );
    // 包含一个指针的可变元组
    let mut mutable_tuple = (Box::new(5u32), 3u32);
    {
        // 解构 `mutable_tuple` 来改变 `last` 的值。
        let (_, ref mut last) = mutable_tuple;
        *last = 2u32;
    }

    println!("tuple is {:?}", mutable_tuple);
}

// 输出结果
ref_c1 equals ref_c2: true
point is (0, 0)
mutable_point is (0, 1)
tuple is (5, 2)

部分引用

fn main() {
    #[derive(Debug)]
    struct Person {
        name: String,
        age: u8,
    }
    let person = Person {
        name: String::from("Alice"),
        age: 20,
    };
    // `name` 从 person 中移走,但 `age` 只是引用
    // 注意name、age属于当前main函数作用域,如果下面语句被{}包裹,作用域就只在{}里面,那么下面的print语句就报错了
    let Person { name, ref age } = person;
    println!("The person's age is {}", age);
    println!("The person's name is {}", name);
    // 报错!部分移动值的借用:`person` 部分借用产生
    //println!("The person struct is {:?}", person);

    // `person` 不能使用,但 `person.age` 因为没有被移动而可以继续使用
    println!("The person's age from person struct is {}", person.age);
}


// 输出结果

3 Self

trait 或 impl 块中的实现类型,或类型定义中的当前类型。相当于 c++ 中的 this

在类型定义中:

struct Node {
    elem: i32,
    // `Self` 在这里是 `Node`。
    next: Option<Box<Self>>,
}

在 impl 块中:

struct Foo(i32);

impl Foo {
    fn new() -> Self {
        Self(0)
    }
}

assert_eq!(Foo::new().0, Foo(0).0);

泛型参数隐含在 Self 中:

struct Wrap<T> {
    elem: T,
}

impl<T> Wrap<T> {
    fn new(elem: T) -> Self {
        Self { elem }
    }
}

在 trait 定义和相关的 impl 块中:

trait Example {
    fn example() -> Self;
}

struct Foo(i32);

impl Example for Foo {
    fn example() -> Self {
        Self(42)
    }
}

assert_eq!(Foo::example().0, Foo(42).0);

4 impl

impl 有 2 种语法,impl ... 是为类型实现方法,另一种 impl ... for ... 是为类型实现 trait。

#![allow(unused)]
fn main() {
    pub trait Summary {
        fn summarize(&self) -> String;
    }

    pub struct NewsArticle {
        pub headline: String,
        pub location: String,
        pub author: String,
        pub content: String,
    }

    impl Summary for NewsArticle {
        fn summarize(&self) -> String {
            format!("{}, by {} ({})", self.headline, self.author, self.location)
        }
    }
    impl NewsArticle {
        fn print(&self) {
            println!("headline:{} location:{} ", self.headline, self.location);
        }
    }
}

5 as

  • as
  • 功能:在类型之间进行转换,或重命名导入。

as 最常用于 将原始类型转换为其他原始类型,但它还有其他用途,包括将 指针转换为地址地址转换为指针 以及将 指针转换为其他指针

let thing1: u8 = 89.0 as u8;
assert_eq!('B' as u32, 66);
assert_eq!(thing1 as char, 'Y');
let thing2: f32 = thing1 as f32 + 10.5;
assert_eq!(true as u8 + thing2 as u8, 100);

通常,任何可以通过指定类型执行的强制转换也可以使用 as 完成,因此,除了编写 let x: u32 = 123 之外,您还可以编写 let x = 123 as u32 (注意:在这种情况下,let x: u32 = 123 最好)。 但是,在另一个方向上并非如此。 显式使用 as 可以允许更多隐式不允许的强制转换,例如更改裸指针的类型或将闭包转换为裸指针。

as 可以被视为 From 和 Into 的原语: as 仅适用于原语 (u8boolstr、指针等),而 From 和 Into 也适用于 String 或 Vec 等类型。

当可以推断目标类型时,as 也可以与 _ 占位符一起使用。请注意,这可能会导致推理中断,通常,此类代码应使用显式类型以确保清晰度和稳定性。 使用 as *const _ 或 as *mut _ 转换指针时,这是最有用的,尽管 as *const _ 推荐使用 cast 方法,而 as *mut _ 则建议使用 同样的: 这些方法使意图更清晰。

as 还用于在 use 和 extern-crate 语句中重命名导入:

use std::{mem as memory, net as network};
// 现在,您可以使用名称 `memory` 和 `network` 来引用 `std::mem` 和 `std::net`。

6 where

  • where
  • 功能:添加使用项必须坚持的约束。 where 允许指定生命周期和泛型参数的约束。 RFC 介绍 where 包含有关关键字的详细信息。

where 可用于 traits 的约束:

fn new<T: Default>() -> T {
    T::default()
}

fn new_where<T>() -> T
where
    T: Default,
{
    T::default()
}

assert_eq!(0.0, new());
assert_eq!(0.0, new_where());

assert_eq!(0, new());
assert_eq!(0, new_where());

where 也可用于生命周期。

这是因为 longer 超过 shorter 而进行编译,因此要遵守约束:

fn select<'short, 'long>(s1: &'short str, s2: &'long str, second: bool) -> &'short str
where
    'long: 'short,
{
    if second { s2 } else { s1 }
}

let outer = String::from("Long living ref");
let longer = &outer;
{
    let inner = String::from("Short living ref");
    let shorter = &inner;

    assert_eq!(select(shorter, longer, false), shorter);
    assert_eq!(select(shorter, longer, true), longer);
}

另一方面,由于缺少 where 'b: 'a 子句,因此无法编译:未知 'b 生命周期的生存时间至少与 'a 一样长,这意味着该函数无法确保其始终返回有效的引用:

fn select<'a, 'b>(s1: &'a str, s2: &'b str, second: bool) -> &'a str
{
    if second { s2 } else { s1 }
}

where 也可用于表达无法用 <T: Trait> 语法编写的更复杂的约束:

fn first_or_default<I>(mut i: I) -> I::Item
where
    I: Iterator,
    I::Item: Default,
{
    i.next().unwrap_or_else(I::Item::default)
}

assert_eq!(first_or_default([1, 2, 3].into_iter()), 1);
assert_eq!(first_or_default(Vec::<i32>::new().into_iter()), 0);

where 在泛型和生命周期参数可用的任何地方都可用,如标准库中的 Cow 类型所示:

pub enum Cow<'a, B>
where
    B: ToOwned + ?Sized,
{
    Borrowed(&'a B),
    Owned(<B as ToOwned>::Owned),
}

7 dyn

dyn 是 trait 对象 类型的前缀。 dyn 关键字用于突出显示对关联 Trait 上的方法的调用是 dynamically dispatched。 要以这种方式使用 trait,它必须是对象安全的。

与泛型参数或 impl Trait 不同,编译器不知道要传递的具体类型。即,类型为 erased。 因此,dyn Trait 引用包含 two 指针。 一个指针指向该数据 (例如,结构体的实例)。 另一个指针指向方法名称为函数指针的 map (称为虚拟方法表或 vtable)。

在运行时,当需要在 dyn Trait 上调用方法时,将查询 vtable 以获取函数指针,然后调用该函数指针。

有关 trait 对象 和 对象安全 的更多信息,请参见引用。

上面的间接调用是在 dyn Trait 上调用函数的额外运行时成本。 动态分配调用的方法通常不能由编译器内联。 但是,dyn Trait 可能会产生比 impl Trait / 泛型参数小的代码,因为该方法不会针对每种具体类型重复。

fn foobar_1(thing: &dyn MyThing) {}     // OK
fn foobar_2(thing: Box<dyn MyThing>) {} // OK
fn foobar_3(thing: MyThing) {}          // ERROR!
// 返回一些实现 Animal 的结构体,但是在编译时我们不知道哪个结构体。
fn random_animal(random_number: f64) -> Box<dyn Animal> {
    if random_number < 0.5 {
        Box::new(Sheep {})
    } else {
        Box::new(Cow {})
    }
}

8 type

  • 功能:为现有类型定义别名。
  • 语法: type Name = ExistingType;

type 并不会创建新的类型:

type Meters = u32;
type Kilograms = u32;

let m: Meters = 3;
let k: Kilograms = 3;

assert_eq!(m, k);

在 traits 中,type 用于声明 关联类型

trait Iterator {
    // 关联类型声明
    type Item;
    fn next(&mut self) -> Option<Self::Item>;
}

struct Once<T>(Option<T>);

impl<T> Iterator for Once<T> {
    // 关联类型定义
    type Item = T;
    fn next(&mut self) -> Option<Self::Item> {
        self.0.take()
    }
}