# learn rust
紀錄一下學習rust 筆記,目前大概會以寫web可能會用到的業務邏輯來看大概會用到rust什麼特性。
https://doc.rust-lang.org/stable/std/string/struct.String.html
http://jxz1.j9p.com/pc/rustqwzn.pdf
https://course.rs/basic/result-error/result.html
https://lotabout.me/2017/rust-error-handling/
https://rustmagazine.github.io/rust_magazine_2021/chapter_3/rust-design-pattern-factory.html
https://ithelp.ithome.com.tw/articles/10202889
https://shihyu.github.io/RustPrimerBook/rcarc/cell.html
https://electronic.blue/blog/2017/04/30-rust-an-introduction-in-oop/
# hello cargo
```rust=
cargo new hello_cargo
```
# hello rust
```rust=
println!("Hello, world! {}", test);
```
# variable area
可以看到 第二個花括號裡面的test 的時候外層的 test 記憶體位置空間已經被清除
其中mut 代表 variable 為可變。
```rust=
fn main() {
let mut test = 0;
test = 120;
{
let test = 200;
println!("Hello, world! {}", test);
}
}
```
當variable 脫離作用域可以發現test 值是無法再次被使用類似c/c++ 傳值或者傳址,某些形況類似泛型好像需要特殊處理後面再說。
```rust=
fn five(x: i32) -> i32 {
x + 1
}
fn main() {
let test=1;
let test2 =five( test);
println!("p.x = {}",test2 );
}
```
為什麼要用& ,原因有可能 x假設傳入到 fucntion 後,出來後x 這個 value 可能會被銷毀。
```rust=
fn five(x: &i32) -> i32 {
x + 1
}
fn main() {
let test=1;
let test2 =five( &test);
println!("p.x = {}",test2 );
}
```
# declare variable
當variable 有明顯變數型態則compiler 則會再編譯階段自動推理變數型態。
```rust=
let guess:
```
```rust=
let guess="test":
let mut guess = String::new();
let guess = 1;
```
強指 i32 type
```rust=
let guess:i32 = 1;
```
# match
這邊可以看到variable guess , 其中又對 guess.trim().parse()返回值使用match做處理 ,其中trim () 為把 guess 字串空白清空,parse 則把 string 自動推理成int ,而match 讓 fucntion 回傳的value 只有兩種狀態
ok和 err 假設真的fucntion 沒有任何問題則 正確地返回 num 這個value 並賦予 guess
否則err (_)則代表任意狀態,則把 guess 設為-1。
```rust=
use std::io;
let mut guess = String::new();
io::stdin().read_line(&mut guess).expect("test"); //test
let guess: i32 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => -1,
};
```
# match fucntion
```rust=
match test_function() {
Ok(num) => println!("result: Is OK: {}", num),
Err(_) => println!("result: Failed te"),
}
```
# panic
程式強迫終止
```rust=
match test_function() {
Ok(num) => println!("result: Is OK: {}", num),
Err(_) => panic!(),
}
```
透過設定環境變數可以發生程式強迫終止可以顯示目前的call stack
RUST_BACKTRACE=1
# custom panic
發生異常中斷則顯示Custom panic hook
```rust=
panic::set_hook(Box::new(|_| {
println!("Custom panic hook");
}));
```
# catch all exception
某些情況可能程式碼有問題但是rust編譯器檢測不出來,我一直在找有相關
類似try catch 功能實現,如下
假設程式在while 迴圈裡 嘗試索引 b[test]則會發生 異常中斷則,我們可以嘗試去攔截這段前間所發生的事再來做處理,當然官方是不建議使用下列程式碼片段。
```rust=
let result = panic::catch_unwind(|| {
let b: [i32; 5] = [1, 2, 3, 4, 5];
// b[4];
// let a = [10, 20, 30, 40, 50];
let mut test = 0;
while test < 6 {
println!("the value is: {}", b[test]);
test = test + 1;
}
for element in b.iter() {
print!("test {}\n", element);
}
for number in (1..4).rev() {
println!("{}!", number);
}
println!("LIFTOFF!!!");
});
match result {
Ok(()) => println!("every thing goes OK"),
Err(_) => println!("catch panic"),
}
```
# 引入外部 rand 包
```toml
[package]
name = "hello-rust"
version = "0.1.0"
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
rand = "0.5.5"
```
產生亂數
```rust=
use rand::Rng;
let secret_number = rand::thread_rng().gen_range(1, 101);
println!("rand {}", secret_number);
```
# tup
```rust=
let tup: (i32, String, u8) = (500, "123qwe".to_string(), 1);
println!("float {}", tup.1);
```
# array
```rust=
let a: [i32; 5] = [1, 2, 3, 4, 5];
let mut b = [3; 5];
```
# 2d array
```rust=
//2D array
//https://t.codebug.vip/questions-2091964.htm
let mut state = [[0i32; 9]; 9];
for x in (0..9) {
for y in (0..9) {
let sum = i32::from(((x as i32) + 1) * ((y as i32) + 1));
state[x][y] = sum;
print!("{}:{} = {} ", x + 1, y + 1, state[x][y]);
}
println!("");
}
```
# string
```rust=
let hello = "Здравствуйте";
let mut s2 = String::from(hello);
let mut s3 = String::new();
```
字串切片
```rust=
let hello = "Здравствуйте";
let mut s = &hello[..];
```
逐一字元
```rust=
for c in "Здравствуйте".chars() {
println!("{}", c);
}
```
逐一字元byte
```rust=
for c in "Здравствуйте".bytes() {
println!("{}", c);
}
```
push char
```rust=
s3.push(c);
```
push str
```rust=
s3.push_str("orld!");
```
# vector
```rust=
let mut v = Vec::new();
v.push(5);
v.push(6);
v.push(7);
v.push(8);
```
walk vector
```rust=
for test in v.iter() {
println!("test {}", test);
}
```
get vector by index
```rust=
let third: &i32 = &v[2];
```
match 攔截index 越界錯誤
```rust=
match v.get(2) {
Some(third) => println!("The third element is {}", third),
None => println!("There is no third element."),
}
```
可變 vector
```rust=
let mut v = vec![100, 32, 57];
for i in &mut v {
*i += 50;
}
for i in &v {
println!("{}", i);
}
```
# hashmap
set hashmap value
```rust=
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"), 50);
cores.insert(String::from("Blue"), 20);
```
get hashmap value
```rust=
let team_name = String::from("Blue");
let score = match scores.get(&team_name) {
Some(val) => val,
None => panic!(),
};
```
# struct
```rust=
pub struct Tweet {
pub username: String,
pub content: String,
pub reply: bool,
pub retweet: bool,
}
impl Summary for Tweet {
fn summarize(&self) -> String {
format!("{}: {}", self.username, self.content)
}
}
pub trait Summary {
fn summarize(&self) -> String;
}
pub fn notify<T: Summary>(item: T) {
println!("Breaking news! {}", item.summarize());
}
let tweet = Tweet {
username: String::from("horse_ebooks"),
content: String::from("of course, as you probably already know, people"),
reply: false,
retweet: false,
};
println!("1 new tweet: {}", tweet.summarize());
notify(tweet);
```
return struct
```rust=
pub fn returns_summarizable() -> impl Summary {
Tweet {
username: String::from("horse_ebooks"),
content: String::from("of course, as you probably already know, people"),
reply: false,
retweet: false,
}
}
let tweet = returns_summarizable();
println!("1 new tweet: {}", tweet.summarize());
```
# enum
```rust=
enum WebEvent {
PageLoad,
PageUnload,
KeyPress(char),
Paste(String),
Click { x: i64, y: i64 },
}
fn inspect(event: WebEvent) {
match event {
WebEvent::PageLoad => println!("page loaded"),
WebEvent::PageUnload => println!("page unloaded"),
WebEvent::KeyPress(c) => println!("pressed '{}'.", c),
WebEvent::Paste(s) => println!("pasted \"{}\".", s),
WebEvent::Click { x, y } => {
println!("clicked at x={}, y={}.", x, y);
}
}
}
let pressed = WebEvent::KeyPress('x');
let pasted = WebEvent::Paste(String::from("my text"));
let click = WebEvent::Click { x: 20, y: 80 };
let load = WebEvent::PageLoad;
let unload = WebEvent::PageUnload;
inspect(pressed);
inspect(pasted);
inspect(click);
inspect(load);
inspect(unload);
```
# unit test
```rust=
cargo test
```
```rust=
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
#[test]
fn it_works2() {
assert_eq!(2 + 2, 4);
}
#[test]
fn it_works3() -> Result<(), String> {
if 2 + 2 == 4 {
Ok(())
} else {
Err(String::from("two plus two does not equal four"))
}
}
}
```
# linked list
```rust=
let mut lst = LinkedList::new();
// inserting at the back
lst.push_front('b'); //b
lst.push_front('l'); //l->b
lst.push_front('u'); //u->l->b
lst.push_front('f'); //f->u->l->b
// pop_back()
println!("The element popped from back: {:?}", lst.pop_back());
// pop_front()
println!("The element popped from front: {:?}", lst.pop_front());
```
# smart pointer
https://rust-algo.club/collections/singly_linked_list/
https://blog.csdn.net/wyansai/article/details/105152547
https://blog.gtwang.org/programming/cpp-smart-pointers/
我覺得這兩篇講得很清楚以C++ smart pointer
https://kheresy.wordpress.com/2012/03/03/c11_smartpointer_p1/
https://kheresy.wordpress.com/2012/03/05/c11_smartpointer_p2/
Box
是一種獨享智能指針,類似C++的unique_ptr
```rust=
Box<T>
let x = Box::new(42);
```
Rc
是一種常見的共享指針,類似C++的shared_ptr
```rust=
Rc<T>
use std::rc::Rc;
let a = Rc::new(42);
let b = Rc::clone(&a);
```
就是差不多的概念,也就是,所謂的所有權在使用完後會進行釋放,或者可以通過move轉移所有權,來避免造成memory 之類的問題。
https://electronic.blue/blog/2016/12/03-rust-an-introduction-reference-and-borrow-checker-2/
Cell
```rust=
use std::cell::Cell;
let num = Cell::new(42);
num.set(123);
assert_eq!(num.get(), 123);
```
refCell
```rust=
use std::cell::RefCell;
let s = RefCell::new(String::from("Hello, "));
// 以可寫的方式 borrow
s.borrow_mut().push_str("World");
// 唯讀的 borrow
println!("{}", s.borrow());
```
# command
```rust=
use std::process::Command;
let mut cmd = Command::new("ls").spawn().expect("Fail to spawn");
cmd.wait().expect("Fail to wait");
```
# thread
```ruby=
use std::thread;
use std::time::Duration;
fn main() {
// 建立執行緒
let handle = thread::spawn(move || {
let half_sec = Duration::from_millis(500);
for _ in 0..10 {
println!("Thread");
// 休息半秒
thread::sleep(half_sec);
}
});
let one_sec = Duration::from_secs(1);
for _ in 0..5 {
println!("Main");
// 休息 1 秒
thread::sleep(one_sec);
}
// 等待子執行緒結束
handle.join().unwrap();
}
```
# unsafe
https://ithelp.ithome.com.tw/articles/10202889
只要使用 unsafe 這個關鍵字就能使用這些不安全的功能,這些功能有:
>直接存取指標
>修改全域變數
>被標記為不安全的方法與 trait
```rust=
// 如果用 new 的話 Vec 是不會分配空間的
let vec = Vec::<i32>::with_capacity(1);
unsafe {
vec.set_len(100);
}
// 這邊可以看到 vec 所分配的大小實際上還是只有 1
println!("{}", vec.capacity());
// 然而因為長度已經被設定成 100 了,所以可以看這邊印出了 100 個元素
println!("{:?}", vec);
```