Rust 学习 07
archive time: 2022-05-20
努力学习 Rust
Struct 方法
struct 方法类似于 Java 里的类中的成员方法和类方法
也就是
- 方法 是在 struct (enum, trait) 的 上下文 中定义的
- 方法的第一个参数是
self
(类似 Python), 表示调用的实例
对应概念叫做 关联函数, 与实例无关, 即不需要使用 self
#[derive(Debug)]
struct Rectangle {
width: u16,
length: u16,
}
// 表示实现结构体相关内容
impl Rectangle {
// 关联函数
pub fn new(width: u16, length: u16) -> Self {
Rectangle { width, length }
}
// 结构体方法
pub fn area(&self) -> u16 {
self.length * self.width
}
}
fn main() {
// 使用关联函数
let rec = Rectangle::new(10, 16);
// 使用结构体方法
println!("{}", rec.area());
}
枚举 (enum)
Rust 里的枚举比 C 或 Java 的枚举要高级很多, 而且还可以使用模式匹配, 是一个很好用的工具
例如:
fn main() {
let ipv4 = IPAddress::IPv4(192, 168, 1, 1);
let ipv6 = IPAddress::IPv6("2001:DB8:2de::e13".to_string());
route(ipv4);
route(ipv6);
}
#[derive(Debug)]
enum IPAddress {
IPv4(u8, u8, u8, u8),
IPv6(String),
}
// 使用枚举类型的函数
fn route(ip_addr: IPAddress) {
println!("{:?}", ip_addr);
}
这里, IPv4
和 IPv6
都是 IPAdress
的 枚举变体
而 IPv4
后面所带的就是每个变体所附带的数据
枚举方法
类似结构体, 枚举也可以定义方法, 即使用 impl
关键字
fn main() {
let ipv4 = IPAddress::IPv4(192, 168, 1, 1);
let ipv6 = IPAddress::IPv6("2001:DB8:2de::e13".to_string());
ipv4.route();
ipv6.route();
}
#[derive(Debug)]
enum IPAddress {
IPv4(u8, u8, u8, u8),
IPv6(String),
}
impl IPAddress {
fn route(&self) {
println!("{:?}", self);
}
}
Option 枚举
Option 和 Haskell 的 Maybe 类型, 有 Some (Just) 和 None (Nothing) 两个变体
例子如下
fn main() {
let some_num: Option<u8> = Some(10);
let nothing: Option<u8> = None;
println!("{}, {}", get_val(some_num), get_val(nothing));
}
fn get_val(opt: Option<u8>) -> i8 {
match opt {
Some(n) => match n.try_into() {
Ok(v) => v,
Err(_) => -1,
},
None => -1,
}
}
下面的 match 就使用了 模式匹配
对于 Option 类型, 我们还可以这样
if let Some(n) = some_num {
println!("{}", n + 10);
}
match
match 是分支语句, 每个 arm (分支) 对应着一个 模式, 例如
match opt {
Some(n) => match n.try_into() {
Ok(v) => v,
Err(_) => -1,
},
None => -1,
}
里的 Some(n)
和 None
就是两个模式, 模式可以包含字面值, 变量名 以及 通配符(_
) 等
这里的 n
就是变量名, 如果 opt 是 Some(_)
这种形式的, 那么就把 Some
里的值赋给 n
来使用
而 None
就是字面值
但是 match 必须要覆盖所有可能, 即匹配 Option 时, 需要处理 Some 和 None 两种形式
Rust 的 match 还可以这样
fn main() {
let x = Some(8u8);
let res = match x {
Some(v) if v < 10 => v + 10,
Some(v) => v,
None => 0,
};
println!("{}", res);
}
即, 使用 if 进行细化筛选
Rust 代码组织
Rust 的代码组织大概可分为
- 包 (package)
- 单元包 (crate)
- 模块 (module)
crate
crate 可以分成 library 和 binary
- Crate Root
- 是源代码文件
- 编译器从这里开始组成 crate 的 root module
- Package
- 只能包含 1 个
Cargo.toml
, 描述了如何构建 - 只能包含一个或零个 library crate
- 可以有任意多个 binary crate
- 最少要有一个 crate
- 只能包含 1 个
Module
Module 多用来控制作用域和私有性
module 用于在一个 crate 里对代码进行分组, 增加易读性和可复用性
module 还可控制项目 (item) 的私有性 (pub), 默认是私有的
建立 module 可以使用 mod 关键字, 而且 mod 之间可以嵌套
- src
- utils
- tools.rs
- mod.rs
- lib.rs
- main.rs
各个文件内的内容如下
/// utils/tools.rs
// 可以定义一些函数和结构体
pub fn mul<T>(a: T, b: T) -> T
where
T: std::ops::Mul<Output = T>,
{
a * b
}
/// utils/mod.rs
// utils 模块的控制文件
pub mod tools;
/// lib.rs
// library crate 的 crate root
mod utils; // 声明 utils mod
// 定义一些函数
pub fn add<T>(a: T, b: T) -> T
where
T: std::ops::Add<Output = T>,
{
a + b
}
/// main.rs
// binary crate 的 crate root
mod utils; // 声明 utils mod
// 使用 mod 函数
use crate::utils::tools::mul;
// 使用项目名调用 library crate 中的内容
use learn_rust::add;
// 主函数
fn main() {
let x = Some(8u8);
let res = match x {
Some(v) if v < 10 => v + 10,
Some(v) => v,
None => 0,
};
println!("{}", res);
// 一些调用示例
println!("{}", add(10, 20));
println!("{}", mul(10, 20));
}
路径
路径可以分为绝对路径和相对路径
绝对路径从 crate
开始
而相对路径从当前模块开始来开始找
对于相对路径, 如果要访问上一级路径, 可以使用 super
关键字
一般推荐绝对路径
私有性
默认的模块和项目都是私有的
如果想要对外开放, 那么可以使用 pub
关键字来开放
对于结构体如果用 pub
修饰了, 那么结构体类型是开放的
但是里面的字段如果没有 pub
修饰, 那么默认还是私有的
// 可以使用 Matrix 类型
pub struct Matrix<T>
where
T: std::ops::Add<Output = T>
+ std::ops::Mul<Output = T>
+ std::ops::Sub<Output = T>
+ Eq
+ PartialEq
+ Ord
+ PartialOrd,
{
// 外部无法访问字段
data: Vec<T>,
pub size: (u16, u16), // 公开
}
但是对于 enum
如果公开了, 那么每个 variant 都是公开的
可以使用
pub use
来重新导出
好, 今天就学到这罢, 摸!