您正在閱讀「Rust Taiwan 2020 讀書會筆記」的一節,歡迎點擊本頁上方的 協助編修。
fn main() {
let v: Vec<()> = vec![(); 10];
// 像是你可以這樣寫
for _i in v {
println!("{:?}", 1);
}
// 雖然你有更簡單的寫法
for _i in 1..10 {
println!("{:?}", 1);
}
}
!
表示enum Void{}
fn print_meow_forever () -> ! {
loop { println!("meow"); }
}
fn main () {
let i = if false {
print_meow_forever();
} else {
100
};
println!("{}", i);
}
turbofish
運算子
fn main () {
let x = "1";
println!("{}", x.parse::<i32>().unwrap());
}
<T>
宣告泛型struct Point<T> { x: T, y: T }
impl
實作 interfacetrait
宣告 interface實作自己的 Add:
trait Add<RHS, Output> {
fn my_add (self, rhs: RHS) -> Output;
}
impl Add<i32, i32> for i32 {
fn my_add (self, rhs: i32) -> i32 {
self + rhs
}
}
impl Add<u32, i32> for u32 {
fn my_add (self, rhs: u32) -> i32 {
(self + rhs) as i32
}
}
fn main () {
let (a, b, c, d) = (1i32, 2i32, 3u32, 4u32);
let x: i32 = a.my_add(b);
let y: i32 = c.my_add(d);
println!("{}", x);
println!("{}", y);
}
標準函式庫裡的 Add trait
pub trait Add<RHS = Self> {
type Output;
fn add (self, rhs: RHS) -> Self::Output;
}
標準函式庫 u32 的加法實作
impl Add for u32 {
type Output = u32;
fn add (self, rhs: u32) -> u32 { self + rhs }
}
標準函式庫 String 的加法實作
impl Add for String {
type Output = String;
fn add (mut self, rhs: &str) -> String {
self.push_str(rhs);
self
}
}
trait 裡的 function 可以有一個 default 的實作
trait Top {
fn wear_top (&mut self, _clothes: String) {
println!("Default: coat");
}
}
trait Bottom {
fn wear_bottom (&mut self, _clothes: String) {
println!("Default: pants");
}
}
struct PersonLikeCoat {
top: String,
bottom: String,
}
impl Top for PersonLikeCoat {}
impl Bottom for PersonLikeCoat {
fn wear_bottom (&mut self, clothes: String) {
self.bottom = clothes;
println!("Changed: {}", self.bottom);
}
}
fn main () {
let mut ballfish = PersonLikeCoat { top: String::from("coat"), bottom: String::from("pants") };
ballfish.wear_top(String::from("sweater"));
ballfish.wear_bottom(String::from("skirt"));
}
trait 的繼承
trait Top {
fn wear_top (&mut self, _clothes: String) {
println!("Default: coat");
}
}
trait Bottom {
fn wear_bottom (&mut self, _clothes: String) {
println!("Default: pants");
}
}
struct Person {
top: String,
bottom: String,
}
impl Top for Person {}
impl Bottom for Person {
fn wear_bottom (&mut self, clothes: String) {
self.bottom = clothes;
println!("Changed: {}", self.bottom);
}
}
trait WholeBody: Top + Bottom {
fn wear_whole_body (&mut self, top: String, bottom: String) {
self.wear_top(top);
self.wear_bottom(bottom);
}
}
impl WholeBody for Person {}
fn main () {
let mut ballfish = Person { top: String::from("coat"), bottom: String::from("pants") };
ballfish.wear_whole_body(String::from("sweater"), String::from("skirt"));
}
語法 fn generic<T: FirstTrait + SecondTrait>(t: T) {}
或 fn generice<T> (t: T) where T: FirstTrait + SecondTrait {}
ex:
trait Top {
fn wear_top (&mut self, _clothes: String) {
println!("Default: coat");
}
}
trait Bottom {
fn wear_bottom (&mut self, _clothes: String) {
println!("Default: pants");
}
}
struct Person {
top: String,
bottom: String,
}
impl Top for Person {}
impl Bottom for Person {
fn wear_bottom (&mut self, clothes: String) {
self.bottom = clothes;
println!("Changed: {}", self.bottom);
}
}
fn go_routin1<P: Top + Bottom> (p: &mut P) {
p.wear_top(String::from("sweater"));
p.wear_bottom(String::from("skirt"));
}
fn go_routin2<P> (p: &mut P) where P: Top + Bottom {
p.wear_top(String::from("sweater"));
p.wear_bottom(String::from("skirt"));
}
fn main () {
let mut ballfish = Person { top: String::from("coat"), bottom: String::from("pants") };
go_routin1::<Person>(&mut ballfish); // ::<Person> 可省
go_routin2::<Person>(&mut ballfish); // ::<Person> 可省
}
pub struct TraitObject {
pub data: *mut (),
pub vtable: *mut (),
}
上面的 struct 來自標準函式庫,但不是真的 trait 物件
data指標指向trait物件儲存的類型資料T
vtable指標指向包含為T實作的virtual table (虛表)
虛表本身是一種struct,包含解構函數、大小、方法等
編譯器只知道trait object的指標,但不知道要呼叫哪個方法
運行期, 會從虛表中查出正確的指標• 再進行動態呼叫
Trait物件的限制
?Sized
如<Self: ?Sized>
,包含所有可確定大小的類型,也就是<T: Sized>
Self: Sized
的約束,且為沒有額外Self類型參數的非泛型方法
// 物件不安全的 trait
trait Foo {
fn bad<T> (&self, x: T);
fn new() -> Self;
}
// 方法一:將不安全的部份拆出去
trait Bar {
fn bad<T> (&self, x: T);
}
trait Foo: Bar {
fn new() -> Self;
}
// 方法二:使用 where
trait Foo {
fn bad<T>(&self, x: T);
fn new() -> Self where self: Sized; // 但這個 trait 作為物件時, new 會無法被呼叫
}
trait Top {
fn wear_top (&mut self, _clothes: String) {
println!("Default: coat");
}
}
trait Bottom {
fn wear_bottom (&mut self, _clothes: String) {
println!("Default: pants");
}
}
struct Person {
top: String,
bottom: String,
}
impl Top for Person {}
impl Bottom for Person {
fn wear_bottom (&mut self, clothes: String) {
self.bottom = clothes;
println!("Changed: {}", self.bottom);
}
}
trait WholeBody: Top + Bottom {
fn wear_whole_body (&mut self, top: String, bottom: String) {
self.wear_top(top);
self.wear_bottom(bottom);
}
}
impl WholeBody for Person {}
fn static_dispatch<P: WholeBody> (p: &mut P) {
p.wear_top(String::from("sweater"));
p.wear_bottom(String::from("skirt"));
}
fn dynamic_dispatch (p: &mut WholeBody) {
p.wear_top(String::from("sweater"));
p.wear_bottom(String::from("skirt"));
}
fn main () {
let mut ballfish = Person { top: String::from("coat"), bottom: String::from("pants") };
static_dispatch::<Person>(&mut ballfish); // ::<Person> 可省
dynamic_dispatch(&mut ballfish);
}
trait Fly {
fn fly(&self) -> bool;
}
struct Duck;
impl Fly for Duck {
fn fly(&self) -> bool {
return true;
}
}
fn fly_static (s: impl Fly) -> bool {
s.fly()
}
fn can_fly (s: impl Fly) -> impl Fly {
if s.fly() {
println!("fly!");
} else {
println!("fell!")
}
s // return s
}
fn main () {
let duck = can_fly(Duck);
}
a
跟 b
,被編譯器認定為不同的 type,所以 sum
會報錯
use std::ops::Add;
fn sum<T>(a: impl Add<Output=T>, b: impl Add<Output=T>) -> T {
a + b
}
dyn Trait
動態分配的型態
fn dyn_can_fly (s: impl Fly+'static) -> Box<dyn Fly> {
if s.fly() {
println!("fly!");
} else {
println!("fell!");
}
Box::new(s)
}
std::marker
裡e
Sized
用來標識編譯期可確定大小的類型,大部份類型都預設定義實作 SizedUnsize
用來標識動態大小類型Copy
用來標識可安全按位複製類型Send
用來標識可跨執行緒安全傳遞值的類型,也就是可以跨執行緒傳遞所有權Sync
用來標識可在執行緒間安全共用參考的類型#[lang = "sized"] // lang 表示 Sized trait 供 Rust 語言本身使用
pub trait Sized {} // 此程式為空,無實作方法
&
*
T
實作Deref<Target=U>
,則使用T
的參考時,參考會被轉型成U
fn foo (s: &[i32]) {
println!("{:?}", s[0]);
}
fn main () {
let a = "hello".to_string();
let b = " world".to_string();
// b 被自動 deref
let c = a + &b;
println!("{:?}", c);
/// &Vec<T> -> &[T]
let v = vec![1, 2, 3];
foo(&v);
let x = Rc::new("hello");
let y = x.clone(); // Rc<&str>
// 如果想要呼叫 &str 的 clone,必須要自己 deref
let z = (*x).clone(); // &str
}
fn main () {
let a = 1u32;
let b = a as u64;
println!("{:?}", a);
println!("{:?}", b);
let c = std::u32::MAX;
let d = c as u16;
println!("{:?}", c);
println!("{:?}", d);
let e = -1i32;
let f = e as u32;
println!("{:?}", e);
println!("{:?}", f);
let a: &'static str = "hello"; // &'static str
let b: &str = a as &str;
let c: &'static str = b as &'static str;
}
struct S(i32);
trait A {
fn test(&self, i: i32);
}
trait B {
fn test(&self, i: i32);
}
impl A for S {
fn test(&self, i: i32) {
println!("From A: {:?}", i);
}
}
impl B for S {
fn test(&self, i: i32) {
println!("From B: {:?}", i)
}
}
fn main () {
let s = S(1);
A::test(&s, 2);
B::test(&s, 3);
<S as A>::test(&s, 4);
<S as B>::test(&s, 5);
}
std::convert
#[derive(Debug)]
struct Person { name: String }
impl Person {
fn new<T: Into<String>>(name: T) -> Person {
Person { name: name.into() }
}
}
fn main () {
let person = Person::new("Alex");
let person = Person::new("Alex".to_string());
println!("{:?}", person);
// String from 的方法
let to_string = "hello".to_string();
let from_string = String::from("hello");
assert_eq!(to_string, from_string);
// 如果 U 實現了 From<T>,則 T 類型的實例,都可以呼叫 into 方法轉換為 U
let a = "hello";
let b: String = a.into();
// 所以一般情況只要實作 From 即可,除非 From 很難實作,才需要實作 Into
}
use std::ops::Add;
#[derive(PartialEq)]
struct Int(i32);
impl Add<i32> for Int {
type Output = i32;
fn add (self, other: i32) -> Self::Output {
(self.0) + other
}
}
impl Add<i32> for Option<Int> {} // (X)
// 因為 Rust 裡 Box 有 #[fundamental] 標籤
impl Add<i32> for Box<Int> {
type Output = i32;
fn add (self, other: i32) -> Self::Output {
(self.0) + other
}
}
fn main () {
assert_eq!(Int(3) + 3, 6);
assert_eq!(Box::new(Int(3)) + 3, 6);
}
重複原則
impl<T> AnyTrait for T {}
impl<T> AnyTrait for T where T: Copy {}
impl<T> AnyTrait for i32 {}
// 效能問題
// 這裡實作了 += 的對應方法
impl<R, T: Add<R> + Clone> AddAssign<R> for T {
fn add_assign(&mut self, rhs: R) {
// clone 會造成效能的負擔,有些類型不需要用 clone 這個方法
// 但因為重複原則,無法限縮實作對象,所以為了效能,很多作法是位每個類型實作 trait
// 造成程式複用度不高
let tmp = self.clone() + rhs;
*self = tmp;
}
}