Rust笔记【1】

  1. 元组和解构语法
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;

  1. 数组类型
    数组定义是方括号:[ ]
    元组定义是小圆括号:( )
    结构体定义是大括号:{ },结构体定义和赋值中,成员用逗号,分隔(c++中使用分号分隔)
let arr = [1, 2, 3];
let sss = ["mon", "tue", "fri"];

let a: [i32; 5]; # 长度为5的整型数组
let b: [3; 5];	# 53

let data = a[0];
  1. 传参、赋值默认都是移动操作。
  2. 引用不移动所有权,默认引用是不可修改的。例如:
let s = String::from("hello");

func(&s);

fn func(str: &string) -> ...
  1. 可变引用:
    如果创建了变量的一个可变引用,就不能再创建对改变量的其他引用(包括可变、不可变引用)。
    在一个作用域内不能有多个可变引用,在不同的作用域、不同时创建多个可变引用。
    如果已经创建一个或多个不可变引用,则不能再创建可变引用。
let mut s = String::from("hello");

func(&mut s);

fn func(str: &mut String) ->...
  1. 引用的个数:
    在一个作用域内:
    1)有一个或多个不变引用,无可变引用。
    2)只有一个可变引用。

注意:作用域结束不是以大括号结束,是以变量最后一次使用结束变量作用域(是没有显式标志)。
例如:

let mut s = String::from("hello");
let r1 = &s; // 没问题
let r2 = &s; // 没问题
println!("{} and {}", r1, r2);
// 此位置之后r1 和r2 不再使用

let r3 = &mut s; // 没问题
println!("{}", r3);
  1. slice是一类引用,引用集合中一段连续的元素序列。
    关键字: 引用,集合,连续片段

字符串slice:

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

fn func(s: &String) -> &str {
    
     ...

字符串字面值是slice
s类型是&str

let s = "hello world";
  1. 结构体
    如果存储引用,则必须指定生命周期。否则编译错误。
struct Rectangle {
    
    
	width: i32,
	height: i32,
}

# 实例化,不需要new,key: value方式赋值。
let retc = Rectangle {
    
    
	width: 10,
	height: 20,
}


  1. 类单元结构体 unit-like struct
    用于在某个类型上实现trait,不存储数据
# 不需要大括号定义成员
struct SomeTrait;

# 实例化,不需要括号,没有成员需要赋值
let obj = SomeTrait;
  1. 结构体更新语法
    用一个已有结构体实例为另一个结构体赋值,新结构体只改变部分成员的值
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,
}
  1. 元组结构体
    为元组指定名称,单独的成员不指定名称。有整体名称,无成员变量名称。
    介于元组(无整体名称,无成员变量名称)和结构体(有整体名称,有成员变量名称)之间 。
    适用于区分不同元组类型(便于重用和区分),不需要(或者很容易)区分成员变量。
    成员变量匿名的struct类型定义。
    注意:结构体定义用大括号{ },元组结构体类似元组定义,使用小括号( )定义和初始化。
struct Color (i32, i32, i32);
struct Point (i32, i32, i32};

let bgColor = (0, 0, 0);
let pointA = (1, 2, 3);
  1. 增加属性,派生Debug trait
    在struct定义前增加:#[derive(Debug)]
    println中使用{:?},不能使用{ }
#[derive(Debug)]
struct Rect {
    
    
    width: i32,
    height: i32,
}

fn main() {
    
    
    let rect = Rect {
    
     width: 20, height: 30 };
    println!("retc: {:?}\n", rect);
}
  1. 常用可派生(系统内置)trait
Debug
Copy
Clone
Default
Hash
PartialEq, Eq
PartialOrd, Ord

  1. Rust中struct定义和C++类定义差别:
    1)结构体(类)的数据成员定义和方法定义分离,c++在类中同时定义数据成员和方法。
    2)c++中方法定义是一次性(或者说集中)定义所有方法,rust中可以多次通过impl定义。
    3)c++中通过继承实现基类或者纯虚类,rust可实现trait(类似于接口interface)定义的接口方法(impl trait_name for struct_name {…} )

  2. 方法
    定义方式和函数类似,差别:
    1)定义在结构体(枚举、trait)上下文中:impl struct_name { }
    2)第一个参数是self,代表调用方法的实例。
    &selfself: &Self的缩写
    3)方法使用self,可获取所有权、不变借用、可变借用。
    4)impl块可以有多个,会自动合并

# 函数示例
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); # 调用函数
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
	}
}

# 多个implimpl Rect {
    
    
	fn isSquare(&self) -> bool {
    
    
		self.width == self.height
	}
}

let r = Rect {
    
     width: 20, height: 30, };
let x = r.area(); # 调用方法
let y = r.isSquare();
  1. 关联函数(像类的静态方法,和实例无关)
    定义在impl块中,没有self参数,通常用于定义new函数,创建关联结构体的实例。
    1)定义在imple中
    2)没有self参数
    3)返回Self类型(关联结构体类型)
    4)使用结构体类型名调用,不用实例调用:Rect::new()
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);
  1. 枚举类型
enum IpAddrKind {
    
    
	V4,
	V6,
}

// 可以替代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();

  1. option
    Rust中没有空值(NULL)。
    Option是一个枚举类型。
    包含在preclude中,不需要显示引入作用域。
    使用Option就必须处理空值,其他不是Option类型的就一定不为空值。
enum Option<T> {
    
    
	None,
	Some(T),
}

let num = Some(5);
let empty: Option<i32> = None;
  1. match运算符
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,
	}
}

  1. 绑定值模式
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
		},
	}
}
  1. 匹配 Option 和 if let
    1)if let工作方式和match相同,是match的一个语法糖
    2)if let后面是:模式 = 表达式
    3)if let匹配match的一个分支,忽略其他值,也可以通过else分支处理。
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
}
  1. 通配模式和 “”占位符
    Rust中match匹配必须是穷尽的。
    1)为所有情况单独处理每个分支,例如enum类型。
    2)使用通配模式,用到匹配的值。
    3)使用占位符“
    ”,和通配模式类似,匹配的值不用,抛弃。
    4)通配符或占位符只能在最后一个分支,否则其后面的分支不会被执行。
let result: i32 = func();
match result {
    
    
	6 => "lucky",
	8 => "money",
	other => println!("the result: {}", other),
}

match result {
    
    
	6 => "lucky",
	8 => "money",
	_ => "ok",
	// 或者完全忽略
	_ => (),
}

猜你喜欢

转载自blog.csdn.net/yinminsumeng/article/details/133984567