Skip to content

Rust 相关知识 ​

rustup 工具使用 ​

shell
# 版本查看
rustc -v

# 版本更新
rustup update
rustup update 1.72.0 # 指定版本

# 环境删除
rustup self uninstall

# 编译文件
rustc xxx.rs # 编译后产生同名可运行文件xxx,利用脚本方式./xxx 运行产物。

Cargo 创建项目 ​

Cargo 是 Rust 的构建系统和包管理器。大多数 Rustacean 们使用 Cargo 来管理他们的 Rust 项目。

shell
# 查看版本号
cargo --version

# 创建项目
cargo new hello-cargo

hello-cargo
├── Cargo.lock
├── Cargo.toml
├── src
│   └── main.rs
└── target
    ├── CACHEDIR.TAG
    └── debug

# 构建项目
cargo build

# 在一个命令中同时编译代码并运行生成的可执行文件
cargo run

# 快速检查代码确保其可以编译,但并不产生可执行文件
cargo check

# 在 target/release 而不是 target/debug 下生成可执行文件。
# 这些优化可以让 Rust 代码运行的更快,不过启用这些优化也需要消耗更长的编译时间。
cargo build --release

# 用来做 lint
cargo clippy

# 自动格式化代码
cargo fmt

crate 增加功能依赖库 ​

在 Cargo.toml 的[dependencies]中添加 rand 依赖

toml
[package]
name = "guessing_game"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
rand = "0.8.3"

使用 cargo build 命令即可下载依赖包后完成编译

Cargo.lock ​

同目录下的 Cargo.lock 确保版本相同,使得重新构建都会产生相同的结果

而 cargo update 命令则会忽略 Cargo.lock 文件,并计算出所有符合 Cargo.toml 声明的最新版本。 比如说 rand 的当前版本设定为 0.8.3,那么 cargo update 回去查找大于或等于 0.8.3 而小于 0.9.0 的版本。

rs
fn main() {
format!      // described above
write!       // first argument is either a &mut io::Write or a &mut fmt::Write, the destination
writeln!     // same as write but appends a newline
print!       // the format string is printed to the standard output
println!     // same as print but appends a newline
eprint!      // the format string is printed to the standard error
eprintln!    // same as eprint but appends a newline
format_args! // described below.
}

语法基础 ​

label 关键字 —— Rust 可以给循环加上标签 ​

rs
fn main() {
    let x = 1;

    // 分别用 'outer 和 'inner 来标记这两个循环
    let z = 'outer: loop {
        let mut y = 1;

        'inner: loop {
            if y == 3 {
                y += 1;
                continue 'inner; // Skips to the next iteration of the 'inner loop
            }

            println!("x:{},y:{}", x, y);

            y += 1;

            if y > 5 {
                // break 'outer; // Breaks out of the 'inner loop
                break 'outer y; // break可以带上返回值
            }
        }
    };
    println!("z: {}", z);
}

// for 循环添加 label 关键字

// fn main() {
//     'outer: for x in 1..=3 {
//         for y in 1..=5 {
//             if y == 3 {
//                 continue 'outer; // Skips the current iteration of the 'outer loop
//             }

//             if x == 2 && y == 4 {
//                 break 'outer; // Breaks out of the 'outer loop
//             }

//             println!("x: {}, y: {}", x, y);
//         }
//     }
// }

所有权 ​

所有权是 Rust 用来管理内存的一套规则。

所有权规则 ​

  • Rust 中每个值都有一个所有者。
  • 一个值同时只能有一个所有者。
  • 当所有者离开作用域范围,这个值将被丢弃。
rs
fn main() {
    // 规则 1:Rust中每个值都有一个所有者
    let s1 = String::from("hello"); // s1 是值 "hello" 的所有者

    {
        // 规则 2:一个值同时只能有一个所有者
        let s2 = s1; // 所有权从 s1 转移到 s2(s1 不再有效)
        // println!("{}", s1); // 这会导致编译时错误,因为 s1 不再有效
        println!("{}", s2); // 这是允许的,因为 s2 现在拥有该值
    } // s2在此处超出范围

    // 规则 3:当所有者离开作用域范围,这个值将被丢弃
    // 由于 s2 超出范围,因此为值 "hello" 分配的内存在此处自动释放。
}

结构体的所有权转移 ​

rs
// 当解构一个变量时,可以同时使用 move 和引用模式绑定的方式。当这么做时,部分 move 就会发生:变量中一部分的所有权被转移给其它变量,而另一部分我们获取了它的引用。
// 在这种情况下,原变量将无法再被使用,但是它没有转移所有权的那一部分依然可以使用,也就是之前被引用的那部分
fn main() {
    #[derive(Debug)]
    struct Person {
        name: String,
        age: Box<u8>,
    }

    let person = Person {
        name: String::from("Alice"),
        age: Box::new(20),
    };

    // 通过这种解构式模式匹配,person.name 的所有权被转移给新的变量 `name`
    // 但是,这里 `age` 变量却是对 person.age 的引用, 这里 ref 的使用相当于: let age = &person.age
    let Person { name, ref age } = person;

    println!("The person's age is {}", age);

    println!("The person's name is {}", name);

    // Error! 原因是 person 的一部分已经被转移了所有权,因此我们无法再使用它
    //println!("The person struct is {:?}", person);

    // 虽然 `person` 作为一个整体无法再被使用,但是 `person.age` 依然可以使用
    println!("The person's age from person struct is {}", person.age);
}

疑难杂症 ​

rust 中怎么判断一个变量的类型 ​

rs
use std::any::type_name;

fn test_type<T>(_:T) {
    println!("{:?}" , { type_name::<T>() });
}

let tup: (i32, f64, u8, bool, &str) = (500, 3.2, 1, false, "Hello World");
println!("{:?}", tup);
println!("{} {}", tup.0, tup.4);

// typeof
test_type(tup); // "(i32, f64, u8, bool, &str)"
test_type(tup.4); // "&str"

let arr: [i32; 5] = [1, 2, 3, 4, 5];
let months: [&str; 3] = ["Jan", "Feb", "Mar"];
test_type(arr); // "[i32; 5]"
test_type(months); // "[&str; 3]"

rust 中如何打印一个结构体变量 ​

rs

// 填空,让代码工作
#[derive(Debug)]
struct User {
    active: bool,
    username: String,
    email: String,
    sign_in_count: u64,
}
fn main() {
    let u1 = User {
        email: String::from("someone@example.com"),
        username: String::from("sunface"),
        active: true,
        sign_in_count: 1,
    };

    let u2 = set_email(u1);
    dbg!(&u2);
    println!("{:?}",u2);
}

fn set_email(u: User) -> User {
    User {
        email: String::from("contact@im.dev"),
        active: false,
        ..u
    }
}

添加 dependencies 依赖进行 cargo build 后一直等待 ​

How-to-build-a-develop-environment-for-rust

用 clash 挂代理不代表命令行中的代理生效,可以通过 clash 的控制面板找到“复制终端代理命令”功能,复制后在终端中输入,便可代理翻墙提高网速下载。

shell
rm -rf ~/.cargo/registry/index/* ~/.cargo/.package-cache

参考文档 ​