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
仅适用于原语 (u8
、bool
、str
、指针等),而 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
可用于 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()
}
}