0%

Rust中的特殊符号

Rust里有很多的特殊符号, 其中有的还有多种用途.
这里总结了一些符号的用法, 有可能有不全, 随时补充吧.

()

单元类型, 一种特殊的唯一类型,
大部分使用在返回值, 可以省略, 相当于Java 方法里的返回void;

1
2
3
4
5
6
7
8
9
# rust
fn do_nothing() -> () {
println!("啥也不做");
}

// 可以省略掉 返回值
fn do_nothing2() {
println!("啥也不做");
}

_

在match里用作匹配剩余分支

1
2
3
4
5
6
7
8
9
10
11
12
13
let triple = (0, -2, 3);
// 试一试 ^ 将不同的值赋给 `triple`

println!("Tell me about {:?}", triple);
// match 可以解构一个元组
match triple {
// 解构出第二个和第三个元素
(0, y, z) => println!("First is `0`, `y` is {:?}, and `z` is {:?}", y, z),
(1, ..) => println!("First is `1` and the rest doesn't matter"),
// `..` 可用来忽略元组的其余部分
_ => println!("It doesn't matter what they are"),
// `_` 表示不将值绑定到变量
}

解构时的不关心的项目

1
2
3
4
5
6
7
8
9
struct Person {
name: String,
age: i32,
}

let peter = Person { name: "Peter".to_string(), age: 10 };
// 只想取出 peter 的 name 到 一个新的变量 peter_name,不关心age
let Person { name: peter_name, age: _ } = peter;
println!("{}", &peter_name);

放到变量名的第一位, 消除unused_variables警告

如果一个声明的变量没有在其他位置使用, 编译器会出现警告, 如果坚持要这么做的话, 需要将变量重命名为以_开头

1
2
3
4
5
6
7
// 编译器会对未使用的变量绑定产生警告;可以给变量名加上下划线前缀来消除警告。
let _unused_variable = 3u32;

// 有时完全不关心变量,但是又必须定义变量的时候,相当于java的ignore变量
for _ in 0..args.count {
println!("Hello {}!", args.name)
}

..

解构时代表剩余的项

数组解构

1
2
3
4
5
let arr = [1, 2, 3, 4, 5];
let [one, other @ .., last] = arr;

println!("{}", one);
println!("{:?}", other);

元组解构

1
2
3
4
5
6
let tup = (4, 2, 3);
let (one, ..) = tup;
// 元组不支持下面的写法
// let (one, b @ ..) = tup;

println!("{}", one);

结构体解构

1
2
3
4
5
6
7
8
struct Person {
name: String,
age: i32,
}
let peter = Person { name: "Peter".to_string(), age: 10 };
// 只想取出 peter 的 name 到 一个新的变量 peter_name,不关心age
let Person { name: peter_name, .. } = peter;
println!("{}", &peter_name);

结构体赋值

相当于JavaScript里的三个点

1
2
3
4
5
6
7
8
9
10
#[derive(Debug)]
struct Person {
name: String,
age: i32,
desc: String,
}

let peter = Person { name: "Peter".to_owned(), age: 10, desc: "备注1".to_owned() };
let adam = Person { name: "adam".to_owned(), ..peter };
println!("{:?}", adam);

range的简写

for里的写法

1
2
3
4
// 循环1到99
for n in 1..=99 {
println!("{}", n);
}

切片里的写法

1
2
let ys: Vec<i32> = vec![1, 2, 3, 4, 5];
let b: &[i32] = &ys[1..4];

match里的写法

1
2
3
4
5
let num: i32 = 10;
match num {
13..19 => println!("{}", "13到18"),
_ => {}
}

->

函数返回值类型

1
2
3
fn gen_0() -> i32 {
0
}

=>

match 分支

1
2
3
4
5
6
7
8
9
10
11
12
13
let triple = (0, -2, 3);
// 试一试 ^ 将不同的值赋给 `triple`

println!("Tell me about {:?}", triple);
// match 可以解构一个元组
match triple {
// 解构出第二个和第三个元素
(0, y, z) => println!("First is `0`, `y` is {:?}, and `z` is {:?}", y, z),
(1, ..) => println!("First is `1` and the rest doesn't matter"),
// `..` 可用来忽略元组的其余部分
_ => println!("It doesn't matter what they are"),
// `_` 表示不将值绑定到变量
}

'

生命期

1
2
3
4
5
// `print_refs` 接受两个 `i32` 的引用,它们有不同的生命周期 `'a` 和 `'b`。
// 这两个生命周期都必须至少要和 `print_refs` 函数一样长。
fn print_refs<'a, 'b>(x: &'a i32, y: &'b i32) {
println!("x is {} and y is {}", x, y);
}

跳出外层循环的标签

在多层循环里,设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
fn main() {
'outer: loop {
println!("Entered the outer loop");

'inner: loop {
println!("Entered the inner loop");

// 这只是中断内部的循环
//break;

// 这会中断外层循环
break 'outer;
}

println!("This point will never be reached");
}

println!("Exited the outer loop");
}

?

解开 Option

跟ES的?方法相同

1
2
3
4
5
6
// 获取此人的工作电话号码的区号(如果存在的话)。
fn work_phone_area_code(&self) -> Option<u8> {
// 没有`?`运算符的话,这将需要很多的嵌套的 `match` 语句。
// 这将需要更多代码——尝试自己编写一下,看看哪个更容易。
self.job?.phone_number?.area_code
}

直接返回Err, 不需要unwrap处理

如果方法返回Result, 相当于Java的异常处理, 那么方法里的语句可以直接抛出.

1
2
3
4
5
6
fn multiply(first_number_str: &str, second_number_str: &str) -> Result<i32, ParseIntError> {
let first_number = first_number_str.parse::<i32>()?;
let second_number = second_number_str.parse::<i32>()?;

Ok(first_number * second_number)
}

&

取引用

1
let a: &i32 = &1;

*

解引用

1
2
let a: &i32 = &1;
let b: i32 = *a;

!

使用 macro_rules! 来创建宏

1
2
3
4
5
6
7
8
// 这是一个简单的宏,名为 `say_hello`。
macro_rules! say_hello {
// `()` 表示此宏不接受任何参数。
() => (
// 此宏将会展开成这个代码块里面的内容。
println!("Hello!");
)
}

调用宏

1
2
3
4
fn main() {
// 这个调用将会展开成 `println("Hello");`!
say_hello!()
}

发散函数(diverging function)

发散函数(diverging function)绝不会返回。 它们使用 ! 标记,这是一个空类型。

1
2
3
fn foo() -> ! {
panic!("This call never returns.");
}

可以被转换为任何其他类型.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
fn main() {
fn sum_odd_numbers(up_to: u32) -> u32 {
let mut acc = 0;
for i in 0..up_to {
// 注意这个 match 表达式的返回值必须为 u32,
// 因为 “addition” 变量是这个类型。
let addition: u32 = match i%2 == 1 {
// “i” 变量的类型为 u32,这毫无问题。
true => i,
// 另一方面,“continue” 表达式不返回 u32,但它仍然没有问题,
// 因为它永远不会返回,因此不会违反匹配表达式的类型要求。
false => continue,
};
acc += addition;
}
acc
}
println!("Sum of odd numbers up to 9 (excluding): {}", sum_odd_numbers(9));
}

这也是永远循环(如 loop {})的函数(如网络服务器)或终止进程的函数(如 exit())的返回类型。

#

属性是应用于某些模块、crate 或项的元数据(metadata)。

1
2
3
// `#[allow(dead_code)]` 属性可以禁用 `dead_code` lint
#[allow(dead_code)]
fn unused_function() {}

<>

泛型定义

1
fn foo<T>(arg: T) { ... }

涡轮鱼

为泛型函数,方法,结构或枚举指定具体类型的情况

泛型函数

1
2
3
pub fn size_of<T>() -> usize

std::mem::size_of::<u8>()

泛型方法

1
2
3
4
5
6
fn parse<F>(&self) -> Result<F, F::Err> where F: FromStr
"2048".parse::<u32>()


fn collect<B>(self) -> B where B: FromIterator<Self::Item>
[1u8, 2, 3, 4].iter().collect::<Vec<_>>()

泛型结构体

1
2
3
4
pub struct Vec<T> { /* fields omitted */ }
Vec::<u8>::new()

std::collections::HashSet::<u8>::with_capacity(10)

泛型枚举

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#[must_use]
pub enum Result<T, E> {
Ok(T),
Err(E),
}

Result::Ok::<u8, ()>(10)
Result::Err::<u8, ()>(())


pub enum Option<T> {
None,
Some(T),
}
None::<u8>.unwrap()

消除重叠 trait

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
fn main() {
let form = Form{
username: "rustacean".to_owned(),
age: 28,
};

// 如果取消注释此行,则会收到一条错误消息,提示 “multiple `get` found”(找到了多个`get`)。
// 因为毕竟有多个名为 `get` 的方法。
// println!("{}", form.get());

let username = <Form as UsernameWidget>::get(&form);
assert_eq!("rustacean".to_owned(), username);
let age = <Form as AgeWidget>::get(&form);
assert_eq!(28, age);
}

:

类型

和TS一样, 变量和参数的类型, 但是返回值类型是->, 可以参照上面的内容.

1
2
// 变量可以给出类型说明。
let logical: bool = true;

泛型约束(bound)

明确规定 类型应实现哪些功能, 相当于Java的extents

1
2
3
4
5
// 定义一个函数 `printer`,接受一个类型为泛型 `T` 的参数,
// 其中 `T` 必须实现 `Display` trait。
fn printer<T: Display>(t: T) {
println!("{}", t);
}

||

闭包参数部分

1
let closure_annotated = |i: i32| -> i32 { i + 1 };

::

调用关联函数

impl块中不以self为第一参数的函数, 相当于Java的静态函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}

impl Rectangle {
fn square(size: u32) -> Rectangle {
Rectangle {
width: size,
height: size,
}
}
}

fn main() {
let sq = Rectangle::square(3);
}

关联类型

泛型地表示这些新类型

1
2
3
4
5
6
7
8
9
10
11
12
#![allow(unused)]
fn main() {
// `A` 和 `B` 在 trait 里面通过 `type` 关键字来定义。
// (注意:此处的 `type` 不同于为类型取别名时的 `type`)。
trait Contains {
type A;
type B;

// 这种语法能够泛型地表示这些新类型。
fn contains(&self, _: &Self::A, _: &Self::B) -> bool;
}
}

模块路径分割的标识符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
mod front_of_house {
mod hosting {
fn add_to_waitlist() {}
}
}

pub fn eat_at_restaurant() {
// Absolute path
crate::front_of_house::hosting::add_to_waitlist();

// Relative path
front_of_house::hosting::add_to_waitlist();
}

@

match匹配时, 绑定变量到名称

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// `age` 函数,返回一个 `u32` 值。
fn age() -> u32 {
15
}

fn main() {
println!("Tell me what type of person you are");

match age() {
0 => println!("I haven't celebrated my first birthday yet"),
// 可以直接匹配(`match`) 1 ..= 12,但那样的话孩子会是几岁?
// 相反,在 1 ..= 12 分支中绑定匹配值到 `n` 。现在年龄就可以读取了。
n @ 1 ..= 12 => println!("I'm a child of age {:?}", n),
n @ 13 ..= 19 => println!("I'm a teen of age {:?}", n),
// 不符合上面的范围。返回结果。
n => println!("I'm an old person of age {:?}", n),
}
}

;

除了放到语句的最后, ;还有以下用法.

定义数组类型

1
2
// 定长数组(类型标记是多余的)
let xs: [i32; 5] = [1, 2, 3, 4, 5];

初始化相同值的数组

1
2
// 所有元素可以初始化成相同的值
let ys: [i32; 500] = [0; 500];

+

泛型多重约束

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
use std::fmt::{Debug, Display};

fn compare_prints<T: Debug + Display>(t: &T) {
println!("Debug: `{:?}`", t);
println!("Display: `{}`", t);
}

fn compare_types<T: Debug, U: Debug>(t: &T, u: &U) {
println!("t: `{:?}", t);
println!("u: `{:?}", u);
}

fn main() {
let string = "words";
let array = [1, 2, 3];
let vec = vec![1, 2, 3];

compare_prints(&string);
//compare_prints(&array);
// 试一试 ^ 将此行注释去掉。

compare_types(&array, &vec);
}

=

impl Trait

impl Trait - 通过例子学 Rust 中文版 (rustwiki.org)

1
2
3
4
5
6
fn combine_vecs(
v: Vec<i32>,
u: Vec<i32>,
) -> impl Iterator<Item=i32> {
v.into_iter().chain(u.into_iter()).cycle()
}

设置类型别名

1
type my32 = i32;

欢迎关注我的其它发布渠道