Skip to content

hnl1/rust-learn-project-todo

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Rust 学习项目: Todo 事项管理

教程:InkSha/rust-tutorial

cargo run -- -h

资源

经验总结

  • 学习过程中关闭 AI 提示,仅保留语言自带的关键字、函数提示
    • vscode 只在当前项目关闭某扩展:扩展 - 指定扩展 - ⚙️ - 禁用(工作区)
  • Rust 编译过程中的报错多个同出、信息丰富、推荐准确、格式友好,多去尝试出错对学习很有帮助
  • 结构体定义和实例化的语法基本一致
    • 整体结构都是名称 + 大括号: 定义时前面多一个 struct 声明
    • 属性声明都用冒号: 定义时用冒号声明类型,实例化时用冒号声明具体的值
    • 不同属性之间都是用逗号连接

Rust、Rustup、Cargo

  • Rust: 我要学习的这门语言
  • Rustup: Rust 安装器和版本管理工具
  • Cargo: Rust 的构建工具和包管理器(对一个 Rust 项目来说的)

在 macOS、Linux 上安装,直接运行官网的这个命令

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

如果报错没有权限写入 .bash_profile,就先把 .bash_profile 文件的所有者改为当前用户,然后就可以正常安装了

sudo chown $(whoami) ~/.bash_profile

stackoverflow: Could not write to .bash_profile when installing Rust on macOS Sierra

安装之后计算机上就有 Rustup、Rust 编译器和 Cargo 了。一般说 Rust 的版本指的就是其编译器的版本,编译器决定了写出 Rust 语法的功能。

# Rustup 这个工具的版本
$ rustup --version
rustup 1.28.2 (e4f3ad6f8 2025-04-28)
info: This is the version for the rustup toolchain manager, not the rustc compiler.
info: The currently active `rustc` version is `rustc 1.88.0 (6b00bc388 2025-06-23)`

# Rust 编译器的版本
$ rustc --version      
rustc 1.88.0 (6b00bc388 2025-06-23)

# Cargo 这个工具的版本
$ cargo --version
cargo 1.88.0 (873a06493 2025-05-10)

Rust 每六周发布一次稳定版,用 rustup update 可以更新 Rustup 自身、编译器、Cargo 这些工具为最新稳定版。Rustup 文档:The rustup book

Cargo: Rust 的构建工具和包管理器。文档:The Cargo Book

  • cargo init 初始化项目
    • cargo init xxx 可以创建并初始化项目
  • cargo run 自动构建项目并运行
    • 可以使用 cargo run --bin foo 的方法运行单独尝试的代码:有时我想临时试验一个代码,可以创建一个 src/bin/foo.rs 文件,然后运行 cargo run --bin foo 即可
    • 所有 -- 前的参数都会传给 Cargo,-- 后的代码会传给我写的程序
      • 例如 cargo run -- -h 就是我的程序的帮助文档
      • cargo run -hcargo run 的帮助文档
  • cargo test 自动构建项目并运行测试
  • cargo add 添加项目依赖
  • cargo --version 查看版本

println! 要加 ! 因为是一个宏调用(macro)

宏(macro)是编译时展开​​(类似代码模板替换),没有函数调用开销,而且可以自定义语法结构

宏的使用格式就是 名称!,比函数调用多一个感叹号

另:Rust 中无法用函数实现可变参数

println 文档

println 中的 ln 是 "line" 的缩写,明确表达 "打印并换行"(print line)的意图,所有平台一致,都会自动在输出结尾会自动追加一个换行符 \n/U+000A,没有回车符 \r/U+000D

println 示例

println!(); // prints just a newline
println!("hello there!");
println!("format {} arguments", "some");
let local_variable = "some";
println!("format {local_variable} arguments");
println!("format {value} arguments", value="some");
println!("{:#?}", (100, 200))   // (
                                //     100,
                                //     200,
                                // )

完整的格式化规则见 std::fmt

宏展开过程

阶段 动作
词法 切成 token
语法 生成带 macro_call!() 节点的 AST
宏展开 递归扫描 AST,把宏节点替换为新的 AST 节点;仍含宏则继续,深度 ≤ 128
声明宏 模式匹配 + 片段替换
过程宏 运行 proc-macro crate,返回 TokenStream 再解析
结果 纯 AST,无宏节点;随后进入语义分析

查看变量类型 type_name_of_val

type_name_of_val 文档

let val = "val";
println!("{}", std::any::type_name_of_val(&val));  // &str

语句有分号 ;,表达式没有分号 ;

注释

只能给人读

  • 行注释、行尾注释 //
  • 块注释、token 中间注释 /* ... */

可以被 rustdoc 读取

  • 文档行注释 ///
  • 文档块注释 /** ... */
  • 模块级文档 //!
  • 模块级块文档 /*! ... */

&str(字符串切片)和 String

&str 的数据是 &[u8] 格式,切片时是对 u8 的切片,因此切片位置如果不在 UTF-8 的合法边界会报错

Rust 的切片不能使用负数索引

Cargo.tomlCargo.lock

  • Cargo.toml
    人类可读的项目清单:用于描述项目依赖项,由开发者编写,使用 cargo 初始化项目或管理三方库的时候也会自动更新

  • Cargo.lock
    Cargo 自动生成的确定性快照:包含有关依赖项的准确信息。由 Cargo 自动维护,不应该被手动编辑。只有当项目是应用时才需要提交 Cargo.lock,库项目不需要

Cargo 在 2010–2014 年首创 “manifest + lockfile” 模式,后来成为 Python(Poetry、uv)、Node、Go 等生态的模板。

TOML 为 Tom’s Obvious, Minimal Language,2013 年由 Tom Preston-Werner 独立提出,非 Rust 社区发明,仅被 Cargo 采用为配置格式

格式化工具 rustfmt

Option & Result

功能 Option Result<T, E>
构造 Some(v) / None Ok(v) / Err(e)
判断 is_some() / is_none() is_ok() / is_err()
变换 map, and_then map, map_err, and_then
传播 let x = opt?; let x = res?;
匹配 match o { Some(v) => _, None => _ } match r { Ok(v) => _, Err(e) => _ }
// Option 变换
let opt = Some(10);
let doubled = opt.map(|x| x * 2);            // Some(20)
let chained = doubled.and_then(|x| Some(x + 3)); // Some(23)

// Result 变换
let res: Result<i32, &str> = Ok(10);
let doubled = res.map(|x| x * 2);                // Ok(20)
let chained = doubled.and_then(|x| Ok(x + 3));   // Ok(23)
let error_msg = res.map_err(|_| "mapped err");   // Ok(10)

快速取值

  • unwrap 直接取出内部值;遇到 None 或 Err 会 panic!

    let x = Some(1).unwrap();     // 1
    let y: i32 = None.unwrap();   // panic!
  • expect(message) 作用同 unwrap,但 panic 时可打印自定义信息

    let x = Some(1).expect("empty"); // 1
    let y = None.expect("empty");    // panic!("empty")
  • unwrap_or(default) 成功/有值时取值,否则返回给定默认值,永不 panic

    let x = None.unwrap_or(0); // 0
  • unwrap_or_else(closure) 成功/有值时取值,否则运行闭包产生默认值,永不 panic

    let x = None.unwrap_or_else(|| 0); // 0
    let y = Err("!").unwrap_or_else(|_| -1); // -1

match

  • 匹配多种值、模式(含 struct/tuple/enum/切片/范围/字面量)
  • 匹配时同时进行变量绑定与解构
  • 穷尽检查:必须覆盖所有可能,可用 _ 兜底
  • 可以作为表达式:每个分支返回统一类型的值
  • 守卫if 条件 在匹配成功后追加额外布尔限制
  • 绑定模式@ 把匹配成功的整体值再绑定到一个名字

TODO

  • 再过一遍教程,看看有什么新的理解和问题
  • 教程里缺少了 create_todo 的改动过程
  • 再完整看下代码有没有什么不理解的

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages