RUST 基础
主要是跟着B站上面的视频学习,代码和相关也是基本上跟着视频自己记下来
-
cargo new xxx;cargo build;cargo run;cargo check(检查语法)
-
执行的文件在target的debug内
-
变量
mut 可变变量
隐藏,在同一个代码段同名变量定义时具有隐藏性,即第二次定义后使用的是使用的第二次定义的类型,将第一次定义的变量隐藏
const 定义常量: const MAXX:u32 = 10000;
-
数据类型(编译器具有自动推导功能,不必须写上变量类型)
bool型
char型在rust语言里面是32位的!char可以是一个汉字
i8 i16 i32 i64 u8 u16 u32 u64 f32 f64
自适应类型(与机器平台有关系) isize usize println!("max = {}",usize::max_value());
数组 [Type; size] size也是数组类型的一部分
let arr: [u32; 5] = [1,2,3,4,5]; show(arr); // 这里会报错,因为size不一致而size也是数组类型的一个部分 fn show(arr:[u32;3]){ for i in &arr{ println!("{}",i); } }
元组 复合类型
let tup: (i32,f32,char) = (-3,3.69,'赞'); println!("{}",tup.0); println!("{}",tup.1); println!("{}",tup.2); let tup = (-3,3.69,'赞'); //自动推导 //元组可拆解 let (x,y,z) = tup; println!("{}",x);
-
函数 蛇形命名法 常量大写字母 类的首字母大写 一般函数等用小写字母
fn other_fun(){ println!("This is a function!"); } fn other_fun1(a:i32,b:u32){ println!("a = {},b = {}",a,b); } fn other_fun2(a:i32,b:i32) -> i32{ let result = a + b; return result; } fn other_fun3(a:i32,b:i32) -> i32{ a + b }
函数定义的时候传入的变量需要有类型
-
语句 执行操作 但是不返回值得指令
let y = 1; //语句,不返回值 let x = (let y = 1); //错误的,因为无返回值,与C++不一样
表达式 会计算一些值
let y = { let x = 1; x + 1; //错误 无发返回 x + 1 //正确,输出y为2 }
-
控制流
println!("y==other");
if y == 1 { println!("y==1"); }else{ println!("y!=1"); } if y == 1 { println!("y==1"); }else if y == 0{ println!("y==0"); }else{ println!("y==other"); }
let中也可以使用if,且if else中得类型应该保持一致
let condition = true; let x = if condition{ 5 }else{ 6 }; println!("{}",x);
loop loop 也可以赋值给let
let mut counter = 0; loop{ println!("loop"); if counter == 10{ break; } counter = counter + 1; } let mut c = 1; let result = loop{ c += 1; if c == 20{ break c * 2; } }; println!("{}",result); //result为40
while 循环
let mut i = 0; while i !=10 { i += 1; } println!("i={}",i);
for 循环
let arr:[u32;5] = [1,2,3,4,5]; //用迭代器 for element in &arr{ println!("element={}",element); }
-
所有权
-
堆和栈
编译的时候数据的类型大小是固定的,就是分配在栈上的
编译的时候数据的类型大小不是固定的,就是分配在堆上的
-
作用域: {}
let x:i32 = 1; { let y:i32 = 2; println!("{}",x); } println!("{}",y); // y的作用域在{}之内,因此下面无法访问到y的值
-
借用/移动
let s1 = String::from("abc"); let s2 = s1; println!("{}",s1);//报错
类似于C++中的浅拷贝,只是对指针复制,没有对指针所指的区域的进行复制
RUST中拷贝后默认s1无效,即s1的所有权移植给了s2,因此s1处于空,无效状态
同时RUST中string存在内存回收,在离开作用域时会自动调用drop完成内存的回收操作,类似于类的析构
-
clone/深拷贝
let s1 = String:from("abc"); let s2 = s1.clone();
再访问s1可以访问,clone可以拷贝数据即进行深拷贝
-
栈上的数据拷贝
let a = 1; let b = a; println!("a = {} , b = {}",a,b);
在栈上的数据执行等号的时候默认进行copy(相当于深拷贝)
类似于C++中int char等相等之后也可以用,但是class类需要自定义深拷贝clone函数
-
常用的具有copy trait有
所有的整型 浮点型 布尔型 字符类型(char) 元组 数组
-
函数和作用域
fn fun(some_string: String){ println!("{}",some_string); } fn fun2(i:i32){ println!("i = {}",i); } fn main(){ let s = String::from("hello"); fun(s); println!("{}",s);//报错 S已经在离开作用域的时候被drop回收了 let x = 5; fun2(x); println!("{}",x); //可以使用,x分配在栈上,是直接进行copy而不是clone }
-
-
引用和借用
fn main(){ let s1 = gives_ownership(); let s2 = String::from("hello"); let s3 = takes_and_gives_back(s2); println!("Hello world!"); } fn gives_ownership() -> String { let s = String::from("hello"); s } fn takes_and_gives_back(s: String) -> String { s }
因为是调用gives_ownership函数,因此调用后将s的作用域返回给s1
因为s2的使用权将传递给s3,所以如果在最后再次调用s2会发现无法使用
会发现上面十分麻烦,所以RUST中存在了引用这个功能
// 引用: 用法&, // 让我们创建一个指向值的应用,但是并不拥有它,因为不拥有这个值,所以,当引用离开其值指向的作用域后也不会被丢弃 // 借用:&mut fn length(s: &String) -> usize{ s.len() } fn modify_s(s: &mut String){ s.push_str(",world"); } fn main(){ let mut s1 = String::from("hello"); let len = length(&s1); let s = &s1; println!("s = {}",s); println!("s1 = {}",s1); println!("len = {}",len); modify_s(&mut s1); println!("s1 = {}",s1); }
引用无法对值进行修改,只是可以去完成访问,如果需要修改一类操作,需要借用
RUST推荐每个变量只有一个数据拥有权(引用or借用),即不可变引用和可变借用不可以针对于同一个变量同时存在,也就是可读和可读可写不能同时存在
但是当我对其中某一个运用完后可以调用另外一个,即可变以后要重新去进行借用,示例代码如下
fn main(){ let mut s = String::from("hello"); let s1 = &s; println!("{}",s1); let s2 = &mut s; s2.push_str(",world!"); println!("{}",s2); }
泉水引用 Wrong
fn main(){ let ref_s = dangle(); } fn bcyx() -> &String{ let s = String::from("hello"); &s }
作用域在函数内回收掉了,但是引用仍然指向内存,并且返回引用,会报错
-
slice
let s = String::from("hello world!"); let h = &s[0..5]; let h = &s[..5]; let h = &s[0..=4]; let h = &s[..=4]; let w = &s[6..];//第六位到结尾 let a = [1,2,3,4]; let sss = &a[1..3]; println!("sss1 = {}",sss[0]); println!("h = {}",h); //输出hello 上面四个情况均一致
-
结构体
-
定义结构体
#[derive(Debug)] struct User { name: String, count:String, nonce: u64, active: bool, }
-
创建结构体实例
let xiaoming = User { name: String::from("xiaoming"), count: String::from("80001000"), nonce: 10000, active:true, }; println!("xiaoming = {:?}", xiaoming);//横着打出来 println!("xiaoming = {:#?}", xiaoming);//结构体
-
修改结构体字段
let mut xiaohuang = User { name: String::from("xiaohuang"), count: String::from("80001000"), nonce: 10000, active:true, }; xiaohuang.nonce = 20000;
-
参数名字和字段名字同名的简写方法
let name = String::from("xiaoxiao"); let count = String::from("89077777"); let nonce = 200000; let active = false; let user1 = User { name, count, nonce, active, };
-
从其他结构体创建实例
let user2 = User { name: String::from("user2"), ..user1 }; println!("name = {}", user2.name); println!("nonce = {}", user2.nonce);
-
元组结构体
//(1)字段没有名字直接.0和.1等 //(2)圆括号 struct Point(i32, i32); let a = Point(10, 20); let b = Point(30, 11); println!("a.x = {}, a.y = {}", a.0, a.1);
-
没有任何字段的类单元结构体
struct A{};
-
打印结构体
//结构体前添加 #[derive(Debug)] # [derive(Debug)] println!("xiaoming = {:?}",xiaoming); //横着打印出来 println!("xiaoming = {:#?}",xiaoming) //自动换行打印
-
-
方法
# [derive(Debug)] struct Dog { name: String, weight: f32, height: f32, } //简单理解成C++中的类函数 impl Dog { fn get_name(&self) -> &str { &(self.name[..]) } fn get_weight(&self) -> f32 { self.weight } //fn get_height(&self) -> f32 { // self.height //} fn show() { println!("oh oh oh"); } } impl Dog{ fn get_height(&self) -> f32 { self.height } } fn main() { let dog = Dog { name: String::from("wangcai"), weight: 100.0, height: 70.5, }; println!("dog = {:#?}", dog); println!("name = {}", dog.get_name()); println!("weight = {}", dog.get_weight()); println!("height = {}", dog.get_height()); Dog::show(); println!("Hello, world!"); }
-
枚举类型与模式匹配
//1、类似于c语言的方式定义 enum IpAddrKind { V4, V6, } struct IpAddr { kind: IpAddrKind, address: String, } //2、rust语言提倡的方式定义 enum IpAddr2 { V4(String), V6(String), } //3、可以是不同类型 enum IpAddr3 { V4(u8, u8, u8, u8), V6(String), } //4、经典用法 enum Message { Quit, Move{x: i32, y: i32}, Write(String), Change(i32, i32, i32), } //等同于 //struct QuitMessage; //类单元结构体 //struct MoveMessage { // x: i32, // y: i32, //} //struct WriteMessage(String) //struct Change(i32, i32, i32) //5、枚举类型的方法以及match impl Message { fn prin(&self) { match *self { Message::Quit => println!("Quit"), Message::Move{x, y} => println!("Move x = {}, y = {}", x, y), Message::Change(a, b, c) => println!("Change a = {}, b = {}, c = {}", a, b, c), _ => println!("Write") //Message::Write(&s) => println!("Write = {}", s) } } } fn main() { let i1 = IpAddr { kind: IpAddrKind::V4, address: String::from("127.0.0.1"), }; let i2 = IpAddr { kind: IpAddrKind::V6, address: String::from("::1"), }; let i1 = IpAddr2::V4(String::from("127.0.0.1")); let i2 = IpAddr2::V6(String::from("::1")); let i1 = IpAddr3::V4(127, 0, 0, 1); let i2 = IpAddr3::V6(String::from("::1")); let quit = Message::Quit; quit.prin(); let mo = Message::Move{x: 10, y: 20}; mo.prin(); let wri = Message::Write(String::from("Hello")); wri.prin(); let change = Message::Change(1, 2, 3); change.prin(); println!("Hello, world!"); }
-
Option
option是标准库定义的一个枚举类型
match一定要处理完Option中所有的情况
enum Option<T> { Some(T), None, }
fn main(){ let some_number = Some(5); let some_string = Some(String::from("123")); let absent_number: Option<i32> = None; let x:i32 = 5; let y:Option<i32> = Some(5); let mut temp:i32 = 0 // let sum = x + y; x和y不是同一个类型 match y{ Some(i) => {temp = i ;} None => {println!("No");} } let sum = x + temp; let result = plus_one(y); match result { Some(i) => println!("result = {}", i), None => println!("nothing"), }; println!("sum = {}",sum); if let Some(value) = plus_one(y) { println!("value = {}", value); } if let Some(value) = plus_one(y) { println!("value = {}", value); } else { println!("do nothing"); } } fn plus_one(x: Option<i32>) -> Option<i32> { match x { None => None, Some(x) => Some(x+1), } }
-
Vector
fn main(){ // 1. 创建空的vector let mut v:Vec<i32> = Vec::new(); v.push(1); // 2. 创建包含初始值的vector let v = vec![1,2,3]; // 3. 丢弃vector { let v1 = vec![1,2,3]; } // 4. 读取元素 let one: &i32 = &v[1]; println!("{}",one); println!("{}",*one); //上面这两种输出的形式一样 应该是存在自动转换功能 match v.get(1){ Some(Value) => println!("value = {}",value), _ => None, } // 5. 更新 let mut v2:Vec<i32> = Vec::new(); v2.push(1); v2.push(2); v2.push(3); // 6. 遍历 // 不可变的遍历 for i in &v2{ println!("{}",i); } // 可变的遍历 for i in &mut v2{ *i += 1; println!("{}",i); } // 7. 使用枚举 enum Context { Text(String), Float(f32), Int(i32), }; let c = vec![ Context::Text(String::from("string")), Context::Int(-1), Context::Float(0.001) ]; // 8. 补充 let mut v = vec![1, 2, 3, 4, 5]; let first = &v[0]; v.push(6); //报错!!!! //不可变引用后使用可变引用不能再使用不可变引用了!!!! println!("first = {}", first); println!("Hello, world!"); }
-
String
//1、创建一个空String //2、通过字面值创建一个String //2.1、使用String::from() //2.2、使用str的方式 //3、更新String //3.1、push_str //3.2、push //3.3、使用“+”合并字符串 //3.4、使用format! //4、String 索引 //5、str 索引 //6、遍历 //6.1、chars //6.2、bytes fn main() { let mut s0 = String::new(); s0.push_str("hello"); println!("s0 = {}", s0); let s1 = String::from("init some thing"); println!("{}", s1); let s1 = "init some thing".to_string(); println!("{}", s1); let mut s2 = String::from("hello"); s2.push_str(", world"); let ss = " !".to_string(); s2.push_str(&ss);//用ss的引用 println!("{}", s2); println!("ss = {}", ss); let mut s2 = String::from("tea"); s2.push('m'); //s2.push('mx'); //error //s2.push("x"); //error println!("{}", s2); let s1 = "hello".to_string(); let s2 = String::from(", world"); let s3 = s1 + &s2; println!("s3 = {}", s3); //println!("s1 = {}", s1); println!("s2 = {}", s2); let s341 = String::from("tic"); let s342 = String::from("tac"); let s343 = String::from("toe"); let s344 = format!("{}-{}-{}", s341, s342, s343); //format!和println!类似 println!("s344 = {}", s344); println!("s341 = {}", s341); println!("s342 = {}", s342); println!("s343 = {}", s343); let s4 = String::from("hello"); //let s41 = s4[0]; println!("s4.len = {}", s4.len()); let s4 = String::from("你好"); println!("s4.len = {}", s4.len()); //let s41 = s4[0]; let hello = "你好"; let h5 = &hello[0..3]; println!("h5 = {}", h5); //let h6 = &hello[0..2]; //println!("h6 = {}", h6); //chars for c in s4.chars() { println!("c = {}", c); } println!("+++++++++++++++"); //bytes for b in s4.bytes() { println!("b = {}", b); } println!("+++++++++++++++"); println!("Hello, world!"); }
-
HashMap
//1、HashMap<K, V> //2、创建HashMap //3、读取 //4、遍历 //5、更新 use std::collections::HashMap; fn main() { let mut scores: HashMap<String, i32> = HashMap::new(); scores.insert(String::from("Blue"), 10); scores.insert(String::from("Red"), 20); let keys = vec![String::from("Blue"), String::from("Red")]; let values = vec![10, 20]; let scores: HashMap<_, _> = keys.iter().zip(values.iter()).collect(); let k = String::from("Blue"); if let Some(v) = scores.get(&k) { //get 返回的是一个Option println!("v = {}", v); } let k = String::from("Yellow"); let v = scores.get(&k); match v { Some(value) => println!("v = {}", value), None => println!("None"), } println!("++++++++++++"); //遍历:会以任意的顺序遍历出来 for (key, value) in &scores { println!("{}, {}", key, value); } println!("++++++++++++"); //直接插入 let mut ss = HashMap::new(); ss.insert(String::from("one"), 1); ss.insert(String::from("two"), 2); ss.insert(String::from("three"), 3); ss.insert(String::from("one"), 3);//覆盖前者 println!("{:?}", ss); //键不存在的时候才插入 let mut ss1 = HashMap::new(); ss1.insert(String::from("one"), 1); ss1.insert(String::from("two"), 2); ss1.insert(String::from("three"), 3); ss1.entry(String::from("one")).or_insert(3); println!("ss1 = {:?}", ss1); //根据旧值来更新一个值 let text = "hello world wonderful world"; let mut map = HashMap::new(); for word in text.split_whitespace() { let count = map.entry(word).or_insert(0); *count += 1; } println!("map = {:?}", map); println!("Hello, world!"); }
-
模块
-
定义
- 包:Cargo的一个功能,允许构建、测试和分享crate
- Crate:一个模块的树形结构,形成库或二进制项目
- 模块:通过use来使用,用来控制作用域和路径的私有性
- 路径
-
包和crate
- crate root是一个源文件,起点
- crate root是src/main.rs或者src/lib.rs,如果只有main.rs说明只有一个crate
- crate将一个作用域的相关功能分组,可以实现多个项目之间的共享
mod factory { pub mod produce_refrigerator { pub fn produce_re() { println!("produce refrigerator!"); } } mod produce_washing_machine { fn produce_washing() { println!("produce washing machine!"); } } } fn main() { factory::produce_refrigerator::produce_re(); println!("Hello, world!"); }
-
-
模块2
创建好的项目里cargo new --lib mylib
//factory.rs pub mod produce_refrigerator { pub fn produce_re() { println!("produce refrigerator!"); } } pub mod produce_washing_machine { pub fn produce_washing() { println!("produce washing machine!"); } pub fn produce_re() { println!("produce washing machine!"); } }
//lib.rs pub mod factory;
先在main的cargo里面添加
[dependencies] mylib = {path = "./mylib"}
在main.rs中利用
//use mylib::factory::produce_refrigerator; //use mylib::factory::produce_refrigerator::produce_re; //use mylib::factory::produce_washing_machine; //use mylib::factory::produce_washing_machine as A; use mylib::factory::*; fn main() { mylib::factory::produce_refrigerator::produce_re(); //绝对路径 produce_refrigerator::produce_re(); //使用use produce_washing_machine::produce_re(); //A::produce_re(); println!("Hello, world!"); }
-
模块3
mod modA { #[derive(Debug)] pub struct A { pub number: i32, name: String, } impl A { pub fn new_a() -> A { A { number: 1, name: String::from("A"), } } pub fn print_a(&self) { println!("number: {}, name: {}", self.number, self.name); } } pub mod modB { pub fn print_B() { println!("B"); } pub mod modC { pub fn print_C() { println!("C"); super::print_B(); } } } } //use modA::A; use modA::A as A1; fn main() { //let a = modA::A::new_a(); //let a = A::new_a(); let a = A1::new_a(); a.print_a(); let number = a.number; //let name = a.name; println!("+++++++++++++"); modA::modB::modC::print_C(); println!("Hello, world!"); }
-
模块4
-
错误1
//1、rust语言将错误分为两个类别:可恢复错误和不可恢复错误 //(1)可恢复错误通常代表向用户报告错误和重试操作是合理的情况,例如未找到文件。rust中使用Result<T,E>来实现。 //(2)不可恢复错误是bug的同义词,如尝试访问超过数组结尾的位置。rust中通过panic!来实现。 //2、panic! //3、使用BACKTRACE=1 //4、Result<T, E> //enum Result<T, E> { // Ok(T), // Err(E), //} //5、简写 use std::fs::File; fn main() { //let f = File::open("hello.txt"); //let r = match f { // Ok(file) => file, // Err(error) => panic!("error: {:?}", error), //}; //let f = File::open("hello.txt").unwrap(); let f = File::open("hello.txt").expect("Failed to open hello.txt"); //panic!("crash here"); }
-
错误2
//1、当编写一个函数,但是该函数可能会失败,此时除了在函数中处理错误外,还可以将错误传给调用者,让调用者决定如何处理,这被称为传播错误。 //2、传播错误的简写方式,提倡的方式 //3、更进一步的简写 //4、什么时候用panic!,什么时候用Result //(1)示例、代码原型、测试用panic!\unwrap\expect //(2)实际项目中应该用Result //5、Option和Result use std::io; use std::io::Read; use std::fs::File; fn main() { println!("Hello, world!"); let r = read_username_from_file(); match r { Ok(s) => println!("s = {}", s), Err(e) => println!("err = {:?}", e), } } //fn read_username_from_file() -> Result<String, io::Error> { // let f = File::open("hello.txt"); // let mut f = match f { // Ok(file) => file, // Err(error) => return Err(error), // }; // // let mut s = String::new(); // match f.read_to_string(&mut s) { // Ok(_) => Ok(s), // Err(error) => Err(error), // } //} // //fn read_username_from_file() -> Result<String, io::Error> { // let mut f = File::open("hello.txt")?; // // let mut s = String::new(); // f.read_to_string(&mut s)?; // Ok(s) //} fn read_username_from_file() -> Result<String, io::Error> { let mut s = String::new(); File::open("hello.txt")?.read_to_string(&mut s)?; Ok(s) }