Rust基础

Rust基础

简介

Rust是由Graydon Hoare于2009年发起的一门系统级、编译型编程语言,其设计准则为“安全,并发,实用”,支持函数式,并发式,过程式以及面向对象的编程风格。

特点

  • 高性能: Rust 速度惊人且内存利用率极高。由于没有运行时和垃圾回收,它能够胜任对性能要求特别高的服务,可以在嵌入式设备上运行,还能轻松和其他语言集成。

  • 可靠性: Rust 丰富的类型系统和所有权模型保证了内存安全和线程安全,让您在编译期就能够消除各种各样的错误。

  • 生产力: Rust 拥有出色的文档、友好的编译器和清晰的错误提示信息, 还集成了一流的工具 —— 包管理器和构建工具, 智能地自动补全和类型检验的多编辑器支持, 以及自动格式化代码等等。

语言特性

  • 所有权:

  • 生命周期:

  • 特性(trait):

  • enum:

  • 异步语法:

所有权、引用/借用(Borrow/Reference)

  • 每个(内存)都绑定(通过let)到一个变量,该变量拥有该(内存)所有权;

  • let 是函数式语言中的绑定(binding),而不是赋值(assignment);

  • &'a T 是 Copy 的,需要的时候就会拷贝。

  • &'a mut T 则不是,如果你用赋值的话,它会move。这就确保了&'a mut T 是一个noalias pointer,不但能够确保安全,还对优化有很大的帮助。

语法基础

循环

rust提供三种循环关键字:

  • for:范围及迭代循环;

  • while:条件循环;

  • loop:无限循环;

rust循环内部控制关键字:

  • continue:

  • break:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// for range
for n in 1..101 {
}
// for iter
let names = vec!["aa", "bb"]
for name in names.iter() {
}

// loop: 无限循环
loop { 
    //...
    continue;  // 跳过本次循环剩下内容,继续下次个循环
    //...
    break;     // 退出循环
}

// while:
let mut n = 1;
while n < 101 {
    n += 1;
    ...    
}

// while let: do loop when let can match
while let Some(i) = optional {
}

函数

1
2
3
4
5
6
7
// 函数
pub fn hello(name: String) -> String {
    format!("Hello, {}!", name);
    let var1 = xx ;
}

mod util;

模式匹配

  • 模式匹配是 Rust 中借鉴函数式语言中的语法,用于为类型的解构提供一个方便的用法;

  • 模式匹配常用在以下语句中:

    • match <value> { ... } ;

    • if let ;

    • while let

    • for

    • 函数参数

    • ...

  • 默认match模式匹配会move被匹配的对象,在pattern中使用ref来获取被匹配对象的引用,来通过引用获取被匹配对象的所有权,避免所有权转移;

  • 相较于&作用于被匹配对象中, ref匹配直接使用于pattern中;

模式匹配位置

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// match
match VALUE {
    PATTERN1 => EXPRESSION1,
    PATTERN2 => EXPRESSION2,
    PATTERN3 => EXPRESSION3,
}

//if let
if let Some(color) = favorite_color {
    println!("Using your favorite color, {}, as the background", color);
} else if let Ok(age) = age {
    if age > 30 {
        println!("Using purple as the background color"); 
    } else {
        println!("Using orange as the background color");
    }
}

//while let
while let Some(top) = stack.pop() {
    println!("{}", top);
}

// for
for (index, value) in v.iter().enumerate() {
    println!("{} is at index {}", value, index);
}

// let PATTERN = EXPRESSION;
let (x, y, z) = (1, 2, 3);

// 函数参数
fn print_coordinates(&(x, y): &(i32, i32)) {
    println!("Current location: ({}, {})", x, y);
}

//

模式匹配语法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
//
match a {
    1 | 2 => println!("1 or 2"),
    3 => println!("three"),
    4..=5 => println!("4,5"),
    Some(x) if x < 5 => println!("less than five: {}", x),
    Some(50) => println!("Got 50"),
    n @ 42 => println!("Answer is {}", n),    // 变量绑定
    Point { x, y: 0 } => println!("On the x axis at {}", x),
    Message::Quit => {
            println!("The Quit variant has no data to destructure.")
    },
    Message::ChangeColor(Color::Rgb(r, g, b)) => {
            println!(
                "Change the color to red {}, green {}, and blue {}",
                r,
                g,
                b
            )
    },
    Message::Hello { id: id_variable @ 3..=7 } => {  //@绑定
        println!("Found an id in range: {}", id_variable)
    },
    (Some(_), Some(_)) => {                            //_
        println!("Can't overwrite an existing customized value");
    },
    (first, _, third, _, fifth) => {
        println!("Some numbers: {}, {}, {}", first, third, fifth)
    },
    Point { x, .. } => println!("x is {}", x),    //..忽略剩余
    (first, .., last) => {
            println!("Some numbers: {}, {}", first, last);
        },
    ([x, b'*', sub @ ..], [y, suby @ ..]) => {    // slice pattern

    },
    _ => println!("anything"),
}

范围(Range)表达式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
// (1..5)是结构体std::ops::Range的一个实例
use std::ops::{Range, RangeInclusive};

assert_eq!((1..5), Range{ start: 1, end: 5 });
// (1..=5)是结构体std::ops::RangeInclusive的一个实例
assert_eq!((1..=5), RangeInclusive::new(1, 5));
// 自带的 sum 方法用于求和
assert_eq!(3+4+5, (3..6).sum());
assert_eq!(3+4+5+6, (3..=6).sum());
(3..6)

// 每个范围都是一个迭代器,可用for 循环打印范围内的元素
for i in (1..5) {
    println!("{}", i);
}
for i in (1..=5) {
    println!("{}", i);
}

  • 定义:macro_rules! macro_name { (pattern) => {do_something} }
  • Rust 宏基于模式匹配;
  • Rust 宏是卫生宏;
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
macro_rules! create_function {
    ($func_name:ident) => (
        fn $func_name() {
            println!("function {:?} is called", stringify!($func_name))
        }
    )
}

fn main() {
    create_function!(foo);
    foo();
}

闭包(Colusure)

  • 闭包是包含了外部变量的函数;

  • 总共有3种类型的闭包:

    • Fn:

    • FnMut

    • FnOnce

  • 闭包可以近似地理解为一个实现了FnOnce、FnMut和Fn其中一个trait的匿名结构体,这个匿名结构体保存捕获的环境中的变量。通过调用trait的方法来执行闭包体中的代码。

1
2
3
let one = 1;
let plus_one = |x: i32| { x + one };
assert_eq!(2, plus_one(1));

生命周期

  • Rust 中的每一个 引用 都有其生命周期,也就是引用保持有效的作用域;

  • 生命周期的主要目标是避免悬垂引用,它会导致程序引用了并非其期望引用的数据;

  • 生命周期注解告诉 Rust 多个引用的泛型生命周期参数如何相互联系;

  • 如果函数有一个生命周期 'ai32 的引用的参数 first,还有另一个同样是生命周期 'ai32 的引用的参数 second,这两个生命周期注解有相同的名称意味着 firstsecond 必须与这相同的泛型生命周期存在得一样久;

1
2
3
&i32        // 没有生命周期的引用
&'a i32     // 有生命周期的引用
&'a mut i32 // 有生命周期的可变引用

Trait(特性)

  • trait(特征)类似于其他语言中的 interface 或者 protocol,指定一个实际类型必须满足的功能集合。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
//定义
trait HasArea {
    fn area(&self) -> f64;
}
// struct
struct Circle{
    x: f64,
    y: f64,
    radius: f64,
}
// 为Circle实现HasArea特性
impl HasArea for Circle {
    fn area(&self) -> f64 {
        std::f64::consts::PI * (self.radius * self.radius)
    }
}

trait 与泛型

1
2
3
4
5
6
7
// where 从句
fn foo<T, K>(x: T, y: K) 
    where T: Clone, K: Clone + Debug {
    x.clone();
    y.clone();
    println!("{:?}", y);
}

属性(attribute)

rust中的属性是一种元数据格式,应用于mod、crate 或项(item)的元数据(metadata)。可以用来:

当属性作用于整个 crate 时,它们的语法为 #![crate_attribute];

当它们用于模块 或项时,语法为 #[item_attribute](注意少了感叹号 !);

属性语法

属性语法形式如下:

1
2
3
4
5
6
7
#![no_std]

#[doc = "example"]

#[allow(unused, clippy::inline_always)]
#[macro_use(foo, bar)]
#[link(name = "CoreFoundation", kind = "framework")]

属性可以接受参数,有不同的语法形式:

  • #[attribute = "value"]
  • #[attribute(key = "value")]
  • #[attribute(value)]

属性可以多个值,它们可以分开到多行中:

1
2
3
4
#[attribute(value, value2)]

#[attribute(value, value2, value3,
            value4, value5)]

属性的分类

属性可以被分为以下四类:

常用属性

Test

test 属性用来把一个函数标记为单元测试函数,这些函数只有在测试模式下(cargo testrustc --test)才会被编译。测试函数没有参数,并且返回值类型必须是以下两种:

  • ()
  • Result<(), E> where E: Error

示例

1
2
3
4
5
6
#[test]
fn test_the_thing() -> io::Result<()> {
    let state = setup_the_thing()?;
    do_the_thing(&state)?;
    Ok(())
}

Derive

derive 属性一般用来为数据类型生成 Trait 实现。

1
2
3
4
5
#[derive(PartialEq, Clone)]
struct Foo<T> {
    a: i32,
    b: T,
}

编译器会自动为 Foo 生成 PartialEq 的实现:

1
2
3
4
5
6
7
8
9
impl<T: PartialEq> PartialEq for Foo<T> {
    fn eq(&self, other: &Foo<T>) -> bool {
        self.a == other.a && self.b == other.b
    }

    fn ne(&self, other: &Foo<T>) -> bool {
        self.a != other.a || self.b != other.b
    }
}

目前 derive 仅支持标准库中部分的 Trait,我们也可以通过 procedural macros 来为自己的 Trait 实现 derive。其实,标准库里也是通过这种方式实现的,比如:Debug

参考

  1. Introduction - The Rust RFC Book
  2. https://www.jianshu.com/p/64d54d39cffb
  3. https://blog.csdn.net/wowotuo/article/details/76375395
  4. https://lotabout.me/2016/rust-lifetime/
  5. https://tonydeng.github.io/2019/11/09/rust-closure-type/
  6. https://rustwiki.org/zh-CN/rust-by-example/attribute.html
updatedupdated2024-05-102024-05-10