程式語言:Rust
官網
Rust Playground(線上撰寫)
簡介:Rust 的特色介紹
因此任何自動的拷貝動作都可以被視為是對執行效能影響很小的,但可手動 clone
若只在堆疊(Stack)上的資料,會自動拷貝,因擁有 Copy Trait,如下型別
官網
Rust Playground(線上撰寫)
簡介:Rust 的特色介紹
學習資源
變數可被遮蔽
線上測試範例
線上測試範例
fn main() { let x = 5; println!("x 的數值為:{}", x); let x = "five"; println!("x 的數值為:{}", x); }
變數宣告
使用前必須有值
線上測試範例
線上測試範例
fn main() { // // type annotations needed let x; println!("x 的數值為:{}", x); // borrow of possibly-uninitialized variable: `x` let x; println!("x 的數值為:{}", x); x=2; // OK let x; x=2; println!("x 的數值為:{}", x); }
宣告時,需指定變數是否可變
線上測試範例
線上測試範例
fn main() { // 不可變 let x = 5; println!("x 的數值為:{}", x); // cannot assign twice to immutable variable `x` x = 6; println!("x 的數值為:{}", x); // 可變 let mut x = 5; println!("x 的數值為:{}", x); x = 6; println!("x 的數值為:{}", x); }
- Rust 中每個數值都會有一個變數作為它的擁有者(owner)。
- 同時間只能有一個擁有者。
- 當擁有者離開作用域時,數值就會被丟棄。
因此任何自動的拷貝動作都可以被視為是對執行效能影響很小的,但可手動 clone
若只在堆疊(Stack)上的資料,會自動拷貝,因擁有 Copy Trait,如下型別
- 所有整數型別像是 u32。
- 布林型別 bool,它只有數值 true 與 false。
- 所有浮點數型別像是 f64。
- 字元型別 char。
- 元組,不過包含的型別也都要有 Copy 才行。比如 (i32, i32) 就有 Copy,但 (i32, String) 則無。
fn main() { { // s 在此處無效,因為它還沒宣告 let s = "hello"; // s 在此開始視為有效 println!("{}", s); // 使用 s } // 此作用域結束, s 不再有效 // cannot find value `s` in this scope println!("{}", s); // 會出錯 //========================================================= let s1 = String::from("hello"); let s2 = s1; // borrow of moved value: `s1` println!("{}", s1); // 會出錯 //========================================================= let x = 5; let y = x; println!("{}", x); // 不會出錯,因為 Copy Trait //========================================================= let s1 = String::from("hello"); let s2 = s1.clone(); println!("s1 = {}, s2 = {}", s1, s2); // 不會出錯,因重新 clone 一份給 s2 }
基本用法,可用引用閃過所有權
線上測試範例
線上測試範例
fn main() { let s1 = String::from("hello"); let s2 = &s1; println!("{} {}", s1, s2); // 不會出錯,因 s2 為引用 //cannot borrow `*s2` as mutable, as it is behind a `&` reference // s2.push_str(", world"); // 因 s2 為不可變引用,故會出錯 // println!("{}", s2); let mut s3 = String::from("hello"); let s4 = &mut s3; s4.push_str(", world"); println!("{}", s4); // cannot borrow `s1` as mutable, as it is not declared as mutable let s5 = &mut s1; s5.push_str(", world"); println!("{}", s5); }限制條件
- 在任何時候,我們要嘛只能有一個可變引用,要嘛可以有任意數量的不可變引用。
- 引用必須永遠有效。
- 同時有兩個以上的指標存取同個資料。
- 至少有一個指標在寫入資料。
- 沒有針對資料的同步存取機制。
fn main() { let mut s = String::from("hello"); let r1 = &mut s; // cannot borrow `s` as mutable more than once at a time let r2 = &mut s; println!("{}, {}", r1, r2); //=================================================== let mut s = String::from("hello"); { let r1 = &mut s; } // r1 離開作用域,所以建立新的引用也不會有問題 let r2 = &mut s; //=================================================== let mut s = String::from("hello"); let r1 = &s; // 沒問題 let r2 = &s; // 沒問題 // cannot borrow `s` as mutable because it is also borrowed as immutable let r3 = &mut s; // 很有問題! println!("{}, {}, and {}", r1, r2, r3); //=================================================== let mut s = String::from("hello"); let r1 = &s; // 沒問題 let r2 = &s; // 沒問題 println!("{} and {}", r1, r2); // r1 和 r2 從此不再使用 let r3 = &mut s; // 沒問題 println!("{}", r3); //=================================================== { let mut s = String::from("hello"); } // s 離開作用域,已被 drop // cannot find value `s` in this scope let r1 = &mut s; // 很有問題! }
線上測試範例
#![allow(unused)] fn main() { use std::fs::File; use std::io; use std::io::Read; fn read_username_from_file() -> Result<String, io::Error> { let f = File::open("hello.txt"); let mut f = match f { Ok(file) => file, Err(e) => return Err(e), }; let mut s = String::new(); match f.read_to_string(&mut s) { Ok(_) => Ok(s), Err(e) => Err(e), } } // 利用 ? 可達到同上的效果 =========================== 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 trait_fn<T: Copy + Debug>(a: T) -> T {} fn trait_where<T>(a: T) -> T where T: Copy + Debug, { } // 以下兩者等同 fn trait_iml(a: impl Copy) -> impl Copy {} fn trait_iml<T: Copy>(a: T) -> impl Copy {} // impl Trait 語法糖,只在輸入參數,回傳型別並不相同 // 故以下兩者不等同 fn trait_iml(a: impl Copy) -> impl Copy {} fn trait_iml<T: Copy>(a: T) -> T {}
生命週期詮釋不會改變引用能存活多久。
就像當函式簽名指定了一個泛型型別參數時,函式便能夠接受任意型別一樣。
函式可以指定一個泛型生命週期參數,這樣函式就能接受任何生命週期。
生命週期詮釋描述了數個引用的生命週期之間互相的關係,而不會影響其生命週期。
當引用沒有顯式詮釋生命週期時,編譯器會用三項規則來推導它們。
就像當函式簽名指定了一個泛型型別參數時,函式便能夠接受任意型別一樣。
函式可以指定一個泛型生命週期參數,這樣函式就能接受任何生命週期。
生命週期詮釋描述了數個引用的生命週期之間互相的關係,而不會影響其生命週期。
當引用沒有顯式詮釋生命週期時,編譯器會用三項規則來推導它們。
- 第一個規則是每個引用都會有自己的生命週期參數。換句話說,一個函式只有一個參數的話,就只會有一個生命週期:
fn foo<'a>(x: &'a i32);
一個函式有兩個參數的話,就會有分別兩個生命週期參數:fn foo<'a, 'b>(x: &'a i32, y: &'b i32)
,以此類推。 - 第二個規則是如果剛好只有一個輸入生命週期參數,該參數就會賦值給所有輸出生命週期參數:
fn foo<'a>(x: &'a i32) -> &'a i32。
- 第三個規則是如果有多個輸入生命週期參數,但其中一個是 &self 或 &mut self,由於這是方法,self 的生命週期會賦值給所有輸出生命週期參數。此規則讓方法更容易讀寫,因為不用寫更多符號出來。
fn main() { let string1 = String::from("abcd"); let string2 = "xyz"; let result = longest(string1.as_str(), string2); println!("最長的字串為 {}", result); } fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { if x.len() > y.len() { x } else { y } }
let 即是一種 模式配對
struct Point { x: i32, y: i32, } fn main() { let p = Point { x: 0, y: 7 }; let Point { x: a, y: b } = p; assert_eq!(0, a); assert_eq!(7, b); }線上測試範例
enum Color { Rgb(i32, i32, i32), Hsv(i32, i32, i32), } enum Message { Quit, Move { x: i32, y: i32 }, Write(String), ChangeColor(Color), } fn main() { let msg = Message::ChangeColor(Color::Hsv(0, 160, 255)); match msg { // 透過 .. 忽略剩餘部分數值 Message::ChangeColor(Color::Rgb(..,b)) => println!( "藍色 {}", b ), // 透過 _ 忽略整個數值 Message::ChangeColor(Color::Hsv(_, s, _)) => println!( "飽和度 {}", s ), // Guards,compiler 無法檢查 if 所有可能性,需搭配 _ => Message::Move{y,..} if y > 0 => println!( "移動 y:{}", y ), // @ 綁定 Message::Move{x: x_variable @ 3..=7, y:_ } => println!( "移動 x:{} 在 3~7", x_variable ), // 透過 ..= 配對數值範圍 只允許使用數字或 char 數值 Message::Move{x: 3..=7, y:_ } => println!( "移動 x 在 3~7" ), // 多重模式 Message::Quit | Message::Write(_)=> println!( "Quit or Write" ), _ => (), } }
詳細請參考連結
#[no_mangle] pub extern "C" fn addition(a: u32, b: u32) -> u32 { a + b }
留言
張貼留言