日常学习

Rust little book

February 20, 2021

Rust little book

rustup: rust complier 的管理工具, 可以方便的切换 stable, beta, and nightly

cargo 是rust的包管理工具, 用来 下载 rust的依赖, 编译, 以及 分发 到 crates.io

cargo 使用笔记:

$ cd hello_world
$ tree .
.
├── Cargo.toml
└── src
    └── main.rs

1 directory, 2 files
fn main() {
    println!("Hello, world!");
}


$ cargo build
   Compiling hello_world v0.1.0 (file:///path/to/package/hello_world)

$ ./target/debug/hello_world
Hello, world!


$ cargo run
   Compiling hello_world v0.1.0 (file:///path/to/package/hello_world)
     Running `target/debug/hello_world`
Hello, world!



$ cargo build --release
   Compiling hello_world v0.1.0 (file:///path/to/package/hello_world)

package 构成:

  .
  ├── Cargo.lock
  ├── Cargo.toml
  ├── src/
  │   ├── lib.rs
  │   ├── main.rs
  │   └── bin/
  │       ├── named-executable.rs
  │       ├── another-executable.rs
  │       └── multi-file-executable/
  │           ├── main.rs
  │           └── some_module.rs
  ├── benches/
  │   ├── large-input.rs
  │   └── multi-file-bench/
  │       ├── main.rs
  │       └── bench_module.rs
  ├── examples/
  │   ├── simple.rs
  │   └── multi-file-example/
  │       ├── main.rs
  │       └── ex_module.rs
  └── tests/
      ├── some-integration-tests.rs
      └── multi-file-test/
          ├── main.rs
          └── test_module.rs

指定 Dependencies:

Workspaces: workspace 下的一系列package 共享同样的Cargo.lock, output dir 等配置(比如profile), workspace下的packages 被称为 workspace members

rustup: 从官方下载rustc, 使能够随意的在 stable, beta, nightly 中切换。 让 cross-compiling 编译变的简单

概念:

toolchain: rustup 不仅可以 安装stable, beta, nightly 三个channel, 还可以安装 其他的 官方 历史版本

<channel>[-<date>][-<host>]

<channel>       = stable|beta|nightly|<major.minor>|<major.minor.patch>
<date>          = YYYY-MM-DD
<host>          = <target-triple>

#+end_src
** 其他命令: 保持 rust 更新: 
#+begin_src 
$ rustup update
info: syncing channel updates for 'stable'
info: downloading component 'rustc'
info: downloading component 'rust-std'
info: downloading component 'rust-docs'
info: downloading component 'cargo'
info: installing component 'rustc'
info: installing component 'rust-std'
info: installing component 'rust-docs'
info: installing component 'cargo'
info: checking for self-updates
info: downloading self-updates

  stable updated: rustc 1.7.0 (a5d1e7a59 2016-02-29)

如上, rustup update 会更新 stable, component, 以及 rustup self, 可以使用 rustup self update 来手动更新rustup

Rust 知识:

std::fmt:

array & Slice

structures: 有三种类型: 1) Tuple struct, 2) classic struct 3) Unit structs

Enums: 包含多个 变体 的 组合项, 任何一个变体 都是一个 正确的 enum 类型

  enum WebEvent {
      // An `enum` may either be `unit-like`,
      PageLoad,
      PageUnload,
      // like tuple structs,
      KeyPress(char),
      Paste(String),
      // or c-like structures.
      Click { x: i64, y: i64 },
  }

  // A function which takes a `WebEvent` enum as an argument and
  // returns nothing.
  fn inspect(event: WebEvent) {
      match event {
          WebEvent::PageLoad => println!("page loaded"),
          WebEvent::PageUnload => println!("page unloaded"),
          // Destructure `c` from inside the `enum`.
          WebEvent::KeyPress(c) => println!("pressed '{}'.", c),
          WebEvent::Paste(s) => println!("pasted \"{}\".", s),
          // Destructure `Click` into `x` and `y`.
          WebEvent::Click { x, y } => {
              println!("clicked at x={}, y={}.", x, y);
          },
      }
  }

Type Alias:type 关键字能够 使用 type Name = ExistingType; 语法来 使用 Name 代替 ExistingType 使用。 Self 是一种Type Alias

const, static

Variable Bindings: 1)变量默认 是不可修改的, 使用mut 改变 2) 可以在内部的scope中 其同样的名字来shadow(即使不可见) 外部的变量 3)可以使用 先声明 后设定数值的形式 使用变量,但是rust 会检查 使用 未定义变量的错误, 来预防因此产生的问题

Types: 1)转换 as关键字 2) type alias: type NanoSecond = u64; 3) 数值的类型,可以添加到 后面最为后缀使用, 例如: 42i32

Conversion: rust 的struct 以及 enum 等自定义类型的 type转换

  1. From & Into:
    • From 为一个类型定义, 如何create self 从 另一个type中转变
    • Into 则是From 的 调用者, From for U 自动实现了 Into for T ( blank implement)
  2. TryFrom & TryInto: 类似于 From & Into 不同的是, 转换可能失败,返回Result
    • ToString & FromStr:
    • ToString: 单独为 String 类型 定义了一个 ToString Trait,但是并不需要直接实现 ToString,而是实现了 fmt::Display 之后 就自动了提供了 ToString 中的to_string 方法
    #[stable(feature = "rust1", since = "1.0.0")]
impl<T: fmt::Display + ?Sized> ToString for T {
    // A common guideline is to not inline generic functions. However,
    // removing `#[inline]` from this method causes non-negligible regressions.
    // See <https://github.com/rust-lang/rust/pull/74852>, the last attempt
    // to try to remove it.
    #[inline]
    default fn to_string(&self) -> String {
        use fmt::Write;
        let mut buf = String::new();
        buf.write_fmt(format_args!("{}", self))
            .expect("a Display implementation returned an error unexpectedly");
        buf
    }
}

FromStr & parse: 将String 转换为其他类型, 只需要实现了 FromStr for struct, 而String 中的parse 方法 只是 对FromStr::from_str(&string) 的调用

Expression: 程序是由一系列表达式组成的, 1) 赋值表达式 用; 结尾, 2) {} 也是表达式, 如果最后一个表达式 以; 结尾,则返回 (), 否则为最后一个表达式的 结果

Flow of control:

Functions:

Modules:

   // This function only gets compiled if the target OS is linux
   #[cfg(target_os = "linux")]
   fn are_you_on_linux() {
       println!("You are running linux!");
   }

   // And this function only gets compiled if the target OS is *not* linux
   #[cfg(not(target_os = "linux"))]
   fn are_you_on_linux() {
       println!("You are *not* running linux!");
   }

   fn main() {
       are_you_on_linux();

       println!("Are you sure?");
       if cfg!(target_os = "linux") {
           println!("Yes. It's definitely linux!");
       } else {
           println!("Yes. It's definitely *not* linux!");
       }
   }

Rust 工具 Trait:

总览:

Trait Desc
Drop 析构函数,当value 被drop时候,自动调用
Sized Marker Trait, 标记 在编译期间能够确定 size的类型(与之对应的 为 动态 sized 比如 slice)
Clone 支持clone方法的类型
Copy Marker Trait, 标记 支持可以 通过简单的 memory byte-for-bytes 复制 来支持 clone的类型
Deref & DerefMut 为 smart 指针 支持的类型
Default 存在default 数值的类型
AsRef & AsMut Conversion traits for borrowing one type of reference from another.
Borrow and BorrowMut Conversion traits, like AsRef/AsMut, but additionally guaranteeing consistent hashing, ordering, and equality.
From and Into Conversion traits for transforming one type of value into another.
ToOwned Conversion trait for converting a reference to an owned value.

Drop:

  1. 定义

     trait Drop {
       fn drop(&mut self);
     }
    
    
     //一个简单的 实现 示例:
    
     struct Appellation {
         name: String,
         nicknames: Vec<String>,
     }
    
     impl Drop for Appellation {
         fn drop(&mut self) {
             print!("Dropping {}", self.name);
             if !self.nicknames.is_empty() {
                 print!(" (AKA {})", self.nicknames.join(", "));
             }
             println!("");
         }
     }
    
    
  2. Drop trait中 drop函数调用的时机:
    • value drop时候调用
    • 在drop 内部的field之前 进行调用,所以 在Appellation 的drop实现中 内部的field 依然可用。
    • 在 drop调用之后 ,依次调用内部的field的 drop 函数,来释放field内存占用。
  3. 何时需要: Drop 一般很少需要自己进行实现。 只有当 自己定义的类型 拥有rust 并不知道如何清理的资源时,才需要实现Drop Trait。比如下面:

    
    struct FileDesc {
        fd: c_int,
    }
    
    impl Drop for FileDesc {
        fn drop(&mut self) {
            let _ = unsafe { libc::close(self.fd) };
        }
    }
    
  4. Drop组成的结构将是 一个 树状的 调用链。链中 链接关系为 field, 每个节点不是自己实现了 Drop,就是链接节点实现了Drop
  5. Drop 与 Copy Trait 存在 互斥关系,即 实现了Drop 则不能实现 Copy。
  6. 标准库中存在一个 drop函数, fn drop(_x: T) {} 函数 拿到 T的ownership,但并不做任何事情。

Sized: 该类型的数值 在内存中 总是 固定的大小,即: 在编译期间 即能够确定空间大小。几乎rust中所有的type都是 Sized,包括 enum 类型,即便Vec 在heap中存在一个变长的内存,但是Vec 本身 是一个指向 内存地址的指针,包含 address, capacity, length 所以 Vec是一个 Size type。

Clone: 复制一个 独立 的 self 并返回它, Self 不应该是unsized, clone一般是 比较耗费资源的操作,所以rust并没有为每个 类型实现它,而是 由我们自己来实现,但是Rc 与 Arc是一个例外,其clone只是简单的增加计数而已。

Copy: 在表达式 A = B中, 将 B赋值给A时 不是转移B的ownership给A,而是 直接 copy 一个 B出来 赋值给A,该种情况即是 实现了 Copy Trait, 比如基本的简单类型。 i32, i64

Deref and DerefMut: rust 将自动尝试使用 两个trait提供的方法 将 类型转换到 需要的类型。即: 如果 deref 能够防止类型的不匹配,那么rust将自动帮我们 插入代码。

Default:为 有明显的理由 提供默认值的 type实现。

AsRef and AsMut: 为类型转换提供了除了 Deref 之外的另外一种方法。 不同于 Deref 能够提供 rust 内部的代码deref()调用的插入, AsRef 仅仅是 提供了 as_ref的 trait

Borrow and BorrowMut: 与 AsRef 相似,如果type impl Borrow 则 能够从type borrow() 出一个 &T, 区别在于 Borrow 添加了一些限制,要求 type 与 &T 能够hash 的数值一样 才行。(rust 并没有强制要求 ,而是 以文档方式要求) 这 为 Hash table 与 tree 的key 比较 提供了方便。

trait Borrow<Borrowed: ?Sized> {
  fn borrow(&self) -> &Borrowed;
}

From and Into: 消耗 type A 的ownership 返回 type B (对比 AsRef Borrow trait 他们并不使用 调用者 的ownership,只是返回一个 reference)

ToOwned: 存在目的是: 为了解决 clone trait 的限制,即 A impl Clone, 则 &A.clone() 将返回 一个A, 但是 对于 &str .clone() 返回 str 则不能接受(因为str 为unsized 类型), 所以 创建了 ToOwned trait:

Cow: Borrow and ToOwned at Work