程式語言: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
}
留言
張貼留言