Rust笔记【2】

  1. vector
// generic template
Vec<T>

// craete a empty vecetor
let v: Vec<i32) = Vec::new();

// use macro vec! to create a vector, which can detect the argument type
let v = vec![1, 2, 3];

v.push(5);
v.pop();

// 使用[],如果索引越界(无效),则panic
let n: &i32 = &v[2];
// 使用get()方法,返回Option类型,可以处理索引越界(无效)的情况,此时返回None
let n: Option<&i32> = v.get(2);

let mut v = vec![1, 2, 3];
let first = &v[0];
// ...
v.push(5); // error,不能在相同作用域内同时存在可变和不可变引用

// 遍历vector,v和i不可变
for i in &v {
    
     
//	... 
}

// 遍历vector,v和i可变
let mut v = vec![1, 2, 3];
for i in &mut v {
    
     
	*i += 2;
}

// vector中只能保存单一类型
// 可使用enum保存多种类型,前提是多种类型是已知的、明确的
enum SpreadsheetCell {
    
    
	Int(i32),
	Float(f64),
	Text(String),
}
let row = vec![
	SpreadsheetCell::Int(3),
	SpreadsheetCell::Text(String::from("blue")),
	SpreadsheetCell::Float(10.12),
];
  1. 字符串
// 创建空字符串
let s = String::new();

// 使用字面量创建字符串,to_string()方法
let mut s = "hello".to_string();

// push string
s.push_str(" world"); // s: hello world
// push char
s.push('!'); // hello world!

// + operator
// 第一个参数移动,第二个参数引用
let s3 = s1 + &s2;

// +运算符使用了add函数
// 如果第二个参数类型是&String,会强制转换为&Str(Deref强制转换)
fn add(self, s: &str) -> String {
    
    ...}

// 复杂字符串拼接用format!宏
let s = format!("{s1}-{s2}+{s3}");

// 不支持索引字符串,
let h = s[0]; // ERROR

// 可以使用字符串slice引用部分字符串
// Unicode使用可变字节数保存字母,如果索引值不是完整字母,则panic,慎用
let s = &hello[0..4];

// 遍历字符串
for c in "hello".chars() {
    
     ... }
for c in "hello".bytes() {
    
     ... }
  1. Hash Map

  2. 泛型,generic,template

// C++ 模板语法,和Rust对比参考
template <typename T, typename S>
T func(S s) {
    
    
	cout << "input: " << s << endl;
	return s.data();
}

template <typename T>
void func2(T t) {
    
    
	cout << "input 2: " << t << endl;
}

template <typename T>
struct Temp
{
    
    
	T data;
	Temp(T&& d): data(d) {
    
    }
	void output() {
    
    
		cout << "data: " << data << endl;
	}
};

int main()
{
    
    
	string str = "hi boy";

	// 1. 函数模板
	// 返回值类型不能自动推导,需要显式的进行模板实例化
	char* ret = func<char*, string>(str);

	// 如果没有返回类型,不需要推导,则不用显式指定模板类型参数,默认函数模板会进行类型的自动推导
	// 以下3中方式是等效的
	func2(str); 
	func2<>(str);
	func2<string>(str>;

	// 2. 类模板
	// 显式或隐式实例化类模板
	Temp<string> temp(str);
	Temp temp(str);
	
	temp.output();
}
// Rust模板定义类似C++中模板实例化的语法,没有template和typename关键字
// 函数和结构体模板定义:
// 在函数名、类名后面添加类型参数声明<T>,模板声明方式类似c++模板显式实例化,
// 声明和显式实例化形式一致(确认??)
// 使用模板,多数情况可以依赖编译器自动推断,不用显式指定类型参数


// 结构体方法模板定义:impl和结构体名后面同时添加类型参数声明<T>(2个<T>)


// 函数模板
fn largest<T> (list: &[T]) -> &T {
    
    ...}

// 类模板
struct Point<T> {
    
    
	x: T,
	y: T,
}

// 类方法的泛型模板,impl后面需要提供类型参数,传递给类名的类型参数
impl<T> Point<T> {
    
    
	fn x(&self) -> &T {
    
    
		&self.x
	}
}

// 特化类型的方法模板,impl后面不需要类型声明,仅在结构体名后面添加具体特化类型的声明<f32>
impl Point<f32> {
    
    
	fn distance_from_origin(&self) -> f32 {
    
    
		(self.x.powi(2) + self.y.powi(2)).sqrt()
	}
}

// impl中指定的类型参数,不同于方法名后面的类型参数,可以分别指定
// impl中的类型参数是类型的类型参数(下例中和Point指定的类型参数一致)
impl<X1, Y1> Point<X1, Y1> {
    
    
	fn mixup<X2, Y2>(self, other: Point<X2, Y2>) -> Point<X1, Y2> {
    
    
		Point {
    
    
			x: self.x,
			y: other.y,
		}
	}
}
  1. 闭包
// 定义函数语法,和闭包语法对比
fn function(x: i32) -> i32 {
    
     x+1 }

// 闭包完整定义和函数fn定义类似,差别:
// 1- 把参数列表()换为||
// 2- 给闭包变量赋值时末尾需要分号,如果在入参时定义匿名闭包,不需要分号
let lambda1 = |x: i32| -> i32 {
    
     x+1 };

// 省略类型:可省略入参和返回值类型,由编译器推断
// 在作用域内,必须被调用,编译器才能推断类型。如果只有定义,没有调用,会报错。
let lambda2 = |x| {
    
     x+1 };

// 省略类型和大括号:只有一个表达式,可省略函数体的大括号{}
let lambda3 = |x| x+1;


// 在一个作用域内,如果可以推断不同的类型,报错
// 注意:闭包只是省略类型,由编译器推断出一种类型,不同于C++中的泛型lambda,后者可以生成适配多种类型的函数
let closure = |x| x;
let a = closure(String::from("hello"));
let b = closure(123);

// 闭包有3中捕获变量的方式:不可变引用、可变引用、移动所有权
let list = Vec![1, 2, 3];
let only_borrow = || println!("readonly: {:?}", list);

let mut borrows_mutably = || list.push(7);

thread::spawn(move || println!("move: {:?}", list)).join().unwrap();


3种捕获方式,可对应3种trait:
1) FnOnce:
被调用一次,
所有闭包至少实现这个trait,
将捕获的值移出闭包体,只实现FnOnce trait

2)FnMut
不会将捕获值移出闭包体
可能会修改捕获值
可调用多次

3)Fn
适用于捕获值既不移出闭包体,也不会修改
多次调用
适用于多次并发场景

// Option的unwrap_or_else方法定义
impl<T> Option<T> {
    
    
	pub fn unwrap_or_else<F> (self, f:F) -> T 
	where 
		F: FnOnce() -> T
	{
    
    
		match self {
    
    
			Some(x) => x,
			None => f(),
		}
	}
}

Rust种函数也是对象,在需要闭包实参的地方,也可以传函数或者方法名:

unwrap_or_else(Vec::new)
#[derive(Debug)]
struct Rect {
    
    
	width: i32,
	height: i32,
}

let mut RectList = vec![
	Rect {
    
     width: 1, height: 2, },
	Rect {
    
     width: 10, height: 20, },
	Rect {
    
     width: 100, height: 200, },
];
// 通过闭包,对结构体的一个成员进行排序
list.sort_by_key(|r| r.width);
  1. 迭代器

// Iterator trait只要求定义一个方法:next
// type Item和Self::Item定义trait关联类型
pub trait Iterator {
    
    
	type Item;
	fn next(&mut self) -> Option<Self::Item>;
	...
}

let v = vec![1, 2, 3];

let i = v.iter();		// 不可变引用
let i = v.iter_mut(); 	// 可变引用
let i = v.into_iter();	// 获取所有权
for val in i {
    
     ... }


适配器是惰性的,需要调用消费适配器的方法,才会实际执行。

let total: i32 = v.iter().sum();

迭代器适配器,把当前迭代器转换为不同类型迭代器,可链式调用。

let v2: Vec<_> = v1.iter().map(|x| x+1).collect();

let v3: Vec<_> = v1.into_iter().filter(|x| x>10).collect();

猜你喜欢

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