速览系列

Cargo:Rust 的构建工具和包管理器

  • cargo build 可以构建项目

  • cargo run 可以运行项目

  • cargo test 可以测试项目

  • cargo doc 可以为项目构建文档

  • cargo publish 可以将库发布到 crates.io

  • cargo --version 检查是否安装了 Rust 和 Cargo

  • cargo new hello-rust 创建新项目

Rust 项目结构

hello-rust
|- Cargo.toml
|- src
  |- main.rs

Cargo.toml 为 Rust 的清单文件。其中包含了项目的元数据和依赖库。

src/main.rs 为编写应用代码的地方。

Rust 语法

// rust 打印 log 方案,
println!("{:?}+{1:#?}, {} + {1} = {2:?}", 1, 2, 3);
println!("rust 字面量 数值 {},{1},{2},{3}", 1, 1_i8, 1_i16, 1_u16);
println!("rust 字面量 数值 {},{1},{2},{3}", 1, 0x1, 0o1, 0b1);

Rust 函数

fn main() {
    fn add1(x: i32) -> i32 {
        return x + 1;
    }
}

闭包/lambda

为什么是竖线 : 与 Smalltalk 和 Ruby 的闭包定义类似

// rust 的 lambda,两个竖线所包裹的就是参数,后面是函数体,可以用花括号(代码块)来添加多条语句
let add3 = |w: i32| w + 3;
println!("{:?} {:?}", add1(6), add3(6))
move 强制闭包获取其使用的环境值的所有权
let equal_to_x = move |z| z == x; // 这里不使用 move 的话,下面还可以继续访问 x 的

Rust 结构体、元组、数组、vector、...

fn main() {
    #[derive(Debug)] // 不需要 println 就不需要加这个
    struct User {
        username: String,
        email: String,
    }
    impl User {
        // 给结构体添加方法的语法
        fn name_email(&self) -> String {
            let mut str: String = self.username.to_owned();
            str.push_str("__");
            str.push_str(&self.email);
            return str;
        }
        // 关联函数
        fn init() -> User {
            User {
                username: String::from("someone"),
                email: String::from("someone@example.com"),
            }
        }
    }
    // 创建User 结构的实例, 需要修改则必须要可变
    let mut user1 = User::init();
    user1.username = String::from("崮生");
    println!("{:?} {:?}", user1.name_email(), user1);
    // 使用结构体更新语法从其他实例创建实例 struct update syntax)
    let user2 = User {
        username: String::from("崮生2"),
        ..user1
    };
    println!("{:?} {:?}", user2.name_email(), user2);
}
println!("rust 元组 {:?} / {:?}", (1, 1_i8), (0, false, 1, true, (0, 1)));
// > rust 元组 (1, 1) / (0, false, 1, true, (0, 1)) 
let xs = [1, 2, 3, 4, 5];
let ys: [i32; 30] = [3; 30]; //长度 30,全部初始化为3
println!("rust 数组 {:?} / {:?}", xs, ys);

一些内置的实用类型

Map : std::collections::HashMap ,

vector

vector 类型是标准库提供的一个 允许 增长和缩小长度的类似数组的集合类型

let v: Vec<i32> = Vec::new();
let v = vec![1, 2, 3];
let v100 = &v[100]; // 这里当索引处没有对应值的时候会 panic
let v100 = v.get(100); // 这里返回的是 Option 💚

枚举

#[derive(Debug)] // 不需要 println 就不需要加这个
enum IpAddrKind {
    V4,
    V6,
}
fn main() {
    println!(
        "{:?} {:?}",
        (|ip: IpAddrKind| ip)(IpAddrKind::V4),
        IpAddrKind::V6
    );
}
enum IpAddr {
    V4(String),
    V6(String),
}

对于 null 问题 rust 中有 Option 枚举以及泛型,

enum Option<T> { // 比 null 更好的选择
    Some(T),
    None,
}

迭代器

迭代器都实现了一个叫做 Iterator 的定义于标准库的 trait。

一些内置的工具类型

这些都在 prelude 中,不需要额外的命名空间指定

enum Result<T, E> { // 用来抛出可恢复错误
    Ok(T),
    Err(E),
}
let r: Result<i32, i32> = Result::Err(1);
r.unwrap(); // 在 r 匹配 Result::Err() 的时候 panic!
enum Option<T> { // 比 null 更好的选择
    Some(T),
    None,
}

Rust 控制流

fn main() {
    let number = 3;

    let number = if number < 5 {
        println!("condition was true");
    } else {
        println!("condition was false");
    }
}
fn main() {
    let number = 3;
    // 注意! 这里的语法似乎不支持 return
    let number = if number < 5 { "4" } else { "7" };
    println!("{:?}", number);
}
fn main() {
    let r = loop {
        println!("loop 可以作为表达式,下面的while不行");
        break 42;
    };
    while r != 0 {
        break;
    }
    for element in (1..r).rev() {
        println!("从41->1: {}", element);
    }
}

math 控制流运算符

#[derive(Debug)] // 不需要 println 就不需要加这个
enum IpAddrKind {
    V4,
    V6(String),
}
fn main() {
    let ip = IpAddrKind::V6("v6 ip".to_owned());
    let ip_tag = match ip {
        IpAddrKind::V4 => "v4".to_owned(),
        IpAddrKind::V6(addr) => addr,
    };
    println!("{:?}", ip_tag); // "v6 ip"
}

if let 简单控制流

fn main() {
    let some_u8_value = Some(0u8);
    if let Some(3) = some_u8_value {
        println!("three");
    }
}

错误 panic!

panic!("") // 抛出一个不可恢复的错误

泛型

泛型数据类型

struct Point<T> {
    x: T,
    y: T,
}

生命周期 也是泛型

trait / 泛型约束

rust 中通过 trait 来定义共享的行为 (我理解成约束)

pub trait Summary {// 声明一个 trait 「Summary」
    fn summarize(&self) -> String;
    fn summarize1(&self) -> String { // 可以添加一个默认实现
        String::from("(Read more...)")
    }
}

pub struct Tweet {
    pub username: String,
    pub content: String,
    pub reply: bool,
    pub retweet: bool,
}
impl Summary for Tweet { // 实现 Summary
    fn summarize(&self) -> String {
        format!("{}: {}", self.username, self.content)
    }
}

Trait Bound 语法

pub fn notify(item: impl Summary)  -> impl Summary { // 函数参数以及返回值 约束!
    println!("Breaking news! {}", item.summarize());
}
pub fn notify(item: impl Summary + Display) {} // 指定多个约束

pub fn notify<T: Summary>(item: T) { // 泛型约束
    println!("Breaking news! {}", item.summarize());
}
fn some_function<T, U>(t: T, u: U) -> i32
    where T: Display + Clone, // 指定多个约束 的语法糖
          U: Clone + Debug
{}

Rust 所有权很重要

所有权(系统)是 Rust 最为与众不同的特性,它让 Rust 无需垃圾回收(garbage collector)即可保障内存安全。因此,理解 Rust 中所有权如何工作是十分重要的。

所有权规则

首先,让我们看一下所有权的规则。当我们通过举例说明时,请谨记这些规则:

  1. Rust 中的每一个值都有一个被称为其 所有者owner )的变量。

  2. 值在任一时刻有且只有一个所有者。

  3. 当所有者(变量)离开作用域,这个值将被丢弃。

fn main() {
    let s1 = String::from("hello");
    let s2 = s1; // 这里将 s1 的值给了 s2, 然后 s1 就不可访问了。这种行为叫做 move

    let s1 = takes_ownership(s2); //s2 的所有权交给了 takes_ownership,所以下面就不能再使用 s2 了
    let s1_len = calculate_length(&s1); // 这里通过引用的方式使用 s1 ,s1 的所有权还在
    println!("{} {}", s1, s1_len);

    fn takes_ownership(some_string: String) -> String {
        println!("{}", some_string);
        return some_string;
    }
    fn calculate_length(s: &String) -> usize {
        return s.len();
    }
}

可变引用 ,使用 &s 获得的值是无法修改的,需要使用 &mut s

可变引用有一个很大的限制:

  • 在特定作用域中的特定数据只能有一个可变引用。(不可变引用可以有多个)

  • 可变引用与不可变引只能选一个

Slices - Rust 程序设计语言 简体中文版 (kaisery.github.io)

生命周期

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

&'a i32     // 带有显式生命周期的引用
&'a mut i32 // 带有显式生命周期的可变引用

项目管理

  • crate 、 super

    • pub

      • pub use / 重导出

  • use

    • as

    • 嵌套路径从一个模块导入多个 use std::{self,cmp::Ordering, io}; , 这里的 self == std

  • 使用外部包 [dependencies]

  • glob 运算符 use std::collections::*;use std::collections 下的公有项全部引入作用域,看上去就是不应该随便用的

学习资料

Rust 程序设计语言 简体中文版

Rust 嵌入式

最佳实践

  • 字符串

    • 拼接 format!("{}-{}-{}", "a", "b", "c")

    • 分割、获取标量list "नमस्ते".chars()

闲评

  • Rust 的 Shadowing 特性 可能是为了弥补一个函数调用就将堆上的数据释放了,而如果通过 return 将所有权转移出来,这个时候如果没有 shadowing 特性命名会让人非常头疼

  • 这里讲的真好, string 确实是个很复杂的东西 字节、标量值和字形簇!天呐!

链接到此文档的相关文档

崮生的rust速览

by 崮生 from 崮生 • 一些随笔 🎨,欢迎 赞助本文
本文欢迎分享与聚合,全文转载未经授权( 联系我)不许可。