- 元组和解构语法
rust
let tup : (i32, f64, u8) = (666, 2.0, 1);
let tup = (666, 2.0, 1);
let (x, y, z) = tup;
let x = tup.0;
let y = tup.1;
let z = tup.2;
- 数组类型
数组定义是方括号:[ ]
元组定义是小圆括号:( )
结构体定义是大括号:{ },结构体定义和赋值中,成员用逗号,分隔(c++中使用分号分隔)
rust
let arr = [1, 2, 3];
let sss = ["mon", "tue", "fri"];
let a: [i32; 5]; # 长度为5的整型数组
let b: [3; 5]; # 5个3
let data = a[0];
- 传参、赋值默认都是移动操作。
- 引用不移动所有权,默认引用是不可修改的。例如:
rust
let s = String::from("hello");
func(&s);
fn func(str: &string) -> ...
- 可变引用:
如果创建了变量的一个可变引用,就不能再创建对改变量的其他引用(包括可变、不可变引用)。
在一个作用域内不能有多个可变引用,在不同的作用域、不同时创建多个可变引用。
如果已经创建一个或多个不可变引用,则不能再创建可变引用。
rust
let mut s = String::from("hello");
func(&mut s);
fn func(str: &mut String) ->...
- 引用的个数:
在一个作用域内:
1)有一个或多个不变引用,无可变引用。
2)只有一个可变引用。
注意:作用域结束不是以大括号结束,是以变量最后一次使用结束变量作用域(是没有显式标志)。
例如:
rust
let mut s = String::from("hello");
let r1 = &s; // 没问题
let r2 = &s; // 没问题
println!("{} and {}", r1, r2);
// 此位置之后r1 和r2 不再使用
let r3 = &mut s; // 没问题
println!("{}", r3);
- slice是一类引用,引用集合中一段连续的元素序列。
关键字: 引用,集合,连续片段
字符串slice:
rust
let slice_name = target_set[start_index .. end_index]
let s = String::from("hello world");
let h = &s[0..5];
let w = &s[6..11];
# 以下几个等效
let h1 = &s[..5];
let w = &s[6..];
let s2 = &s[..];
字符串slice类型声明:&str
rust
fn func(s: &String) -> &str { ...
字符串字面值是slice
s类型是&str
rust
let s = "hello world";
- 结构体
如果存储引用,则必须指定生命周期。否则编译错误。
rust
struct Rectangle {
width: i32,
height: i32,
}
# 实例化,不需要new,key: value方式赋值。
let retc = Rectangle {
width: 10,
height: 20,
}
- 类单元结构体 unit-like struct
用于在某个类型上实现trait,不存储数据
rust
# 不需要大括号定义成员
struct SomeTrait;
# 实例化,不需要括号,没有成员需要赋值
let obj = SomeTrait;
- 结构体更新语法
用一个已有结构体实例为另一个结构体赋值,新结构体只改变部分成员的值
rust
struct User {
a: i32,
b: i32,
c: i32,
}
let u1 = User {
a: 1,
b: 2,
c: 3,
};
# ..u1(u1为已有结构体实例)必须放到最后
# 除明确复制的字段(b),其他字段值使用u1实例的
# 结构体更新语法,移动了数据,对于不支持copy trait的类型,更新后,原实例对象不可用。
let u2 = u1 {
b: 99,
..u1,
}
- 元组结构体
为元组指定名称,单独的成员不指定名称。有整体名称,无成员变量名称。
介于元组(无整体名称,无成员变量名称)和结构体(有整体名称,有成员变量名称)之间 。
适用于区分不同元组类型(便于重用和区分),不需要(或者很容易)区分成员变量。
成员变量匿名的struct类型定义。
rust
struct Color {i32, i32, i32};
struct Point {i32, i32, i32};
let bgColor = {0, 0, 0};
let pointA = {1, 2, 3};
- 增加属性,派生Debug trait
在struct定义前增加:#[derive(Debug)]
println中使用{:?}
,不能使用{ }
rust
#[derive(Debug)]
struct Rect {
width: i32,
height: i32,
}
fn main() {
let rect = Rect { width: 20, height: 30 };
println!("retc: {:?}\n", rect);
}
- 常用可派生trait
rust
Debug
Copy
Clone
Default
Hash
PartialEq, Eq
PartialOrd, Ord
- 方法
定义方式和函数类似,差别:
1)定义在结构体(枚举、trait)上下文中:impl struct_name { }
2)第一个参数是self,代表调用方法的实例。
&self
是self: &Self
的缩写
3)方法使用self,可获取所有权、不变借用、可变借用。
4)impl块可以有多个,会自动合并
rust
# 函数示例
struct Rect {
width: i32,
height: i32,
}
fn area(rect: &Rect) -> i32 {
rect.width * rect.height
}
let r = Rect { width: 20, height: 30, };
let a = area(&r); # 调用函数
rust
struct Rect {
width: i32,
height: i32,
}
# 定义方法,
# 1. 在某个struct类型中:impl Rect { }
# 2. 第一个参数为:&self
# 3. 调用方式,通过实例调用:r.area()
impl Rect {
fn area(&self) -> i32 {
self.width * self.height
}
}
# 多个impl块
impl Rect {
fn isSquare(&self) -> bool {
self.width == self.height
}
}
let r = Rect { width: 20, height: 30, };
let x = r.area(); # 调用方法
let y = r.isSquare();
- 关联函数(像类的静态方法,和实例无关)
定义在impl块中,没有self参数,通常用于定义new函数,创建关联结构体的实例。
1)定义在imple中
2)没有self参数
3)返回Self类型(关联结构体类型)
4)使用结构体类型名调用,不用实例调用:Rect::new()
rust
struct Rect {
w: i32,
h: i32,
}
impl Rect {
fn new (a: i32, b: i32) -> Self {
Self {
w: a,
h: b,
}
} // fn new
} // impl
let r = Rect::new(20, 30);
- 枚举类型
rust
enum IpAddrKind {
V4,
V6,
}
rust
// 可以替代enum + struct
// 枚举成员可以是各种类型值,不同成员可以是不同类型。
// 枚举类型成员名字,也是一个构建枚举类型实例的函数。
enum IpAddrKind {
V4 (u8, u8, u8, u8),
V6 (String),
}
let four = IpAddrKind::V4;
struct Ipv4Addr {
//...
}
struct Ipv6Addr {
//...
}
// enum成员是struct类型
enum IpAddr {
V4(Ipv4Addr),
V6(Ipv6Addr),
}
// 成员多种不同类型
enum Message {
Quit,
Move {x: i32, y:i32, },
Write (String),
ChangeColor(i32, i32, i32),
}
// 在impl块中增加方法定义
impl Message {
fn call(&self) {
// ...
}
}
let m = Message::Write(String::from("hello"));
m.call();
- option
Rust中没有空值(NULL)。
Option是一个枚举类型。
包含在preclude中,不需要显示引入作用域。
使用Option就必须处理空值,其他不是Option类型的就一定不为空值。
rust
enum Option<T> {
None,
Some(T),
}
let num = Some(5);
let empty: Option<i32> = None;
- match运算符
rust
enum Week {
Mon,
Tue,
Sat,
Sun,
}
fn query(day: Week) -> i32 {
match day {
Week::Mon => 1,
Week::Tue => {
println!("...");
2
// }后面的,是可选的
},
Week::Sat => 6,
Week::Sun => 7,
}
}
- 绑定值模式
rust
struct Ipv4Addr {
//...
}
struct Ipv6Addr {
//...
}
// enum成员是struct类型
enum IpAddr {
V4(Ipv4Addr),
V6(Ipv6Addr),
}
// 在match匹配过程中,把值绑定到变量
fn process(data: IpAddr) {
match data {
IpAddr::V4 (addr4) => {
// consume addr4
},
IpAddr::V6 (addr6) => {
// consume addr6
},
}
}
- 匹配 Option 和 if let
1)if let工作方式和match相同,是match的一个语法糖
2)if let后面是:模式 = 表达式
3)if let匹配match的一个分支,忽略其他值,也可以通过else分支处理。
rust
fn func(x: Option<i32>) -> Option<i32> {
match x {
None => None,
Some(i) => Some(i+1),
}
}
let num = Some(12);
let res2 = func(num);
let res3 = func(None);
// 和上面match等价
if let Some(i) = num {
Some(i+1)
} else {
None
}
- 通配模式和 ""占位符
Rust中match匹配必须是穷尽的。
1)为所有情况单独处理每个分支,例如enum类型。
2)使用通配模式,用到匹配的值。
3)使用占位符" ",和通配模式类似,匹配的值不用,抛弃。
4)通配符或占位符只能在最后一个分支,否则其后面的分支不会被执行。
rust
let result: i32 = func();
match result {
6 => "lucky",
8 => "money",
other => println!("the result: {}", other),
}
match result {
6 => "lucky",
8 => "money",
_ => "ok",
// 或者完全忽略
_ => (),
}