Rust Book Lang Ch.19 Fully Qualified Syntax, Supertraits, Newtype Pattern, type aliases, never type, dynamic sized type
Fully Qualified Syntax
当多个traits和struct具有相同的方法名时,默认会调用直接实现给这个struct的方法,要调用Trait中重名的方法,最好直接使用traitname::method(...)的方式。尤其是如果只是trait中associated functions即trait相关函数,需要<A as TraitB>::method这样的方式调用,这种方式称为fully qualified syntax,基本格式:<Type as Trait>::function(receiver_if_method, next_arg, ...);
fn main() { let person = Human; Pilot::fly(&person);
//traitname: Pilot Wizard::fly(&person); person.fly(); }
trait Animal { fn baby_name() -> String; } struct Dog; impl Dog { fn baby_name() -> String { String::from("Spot") } } impl Animal for Dog { fn baby_name() -> String { String::from("puppy") } } fn main() { println!("A baby dog is called a {}", Dog::baby_name()); println!("A baby dog is called a {}", Animal::baby_name()); }
Supertraits
有时,一个特性要求实现该特性的类型中另外一个特性已经被实现了或者要利用另外一个特性,那么就用trait traitA: superTraitB这样的语法实现,编译的时候就会提醒程序员该类型中要实现另外一个特性。
use std::fmt; trait OutlinePrint: fmt::Display { fn outline_print(&self) { let output = self.to_string(); let len = output.len(); println!("{}", "*".repeat(len + 4)); println!("*{}*", " ".repeat(len + 2)); println!("* {} *", output); println!("*{}*", " ".repeat(len + 2)); println!("{}", "*".repeat(len + 4)); } }
impl OutlinePrint for Point {} ^^^^^^^^^^^^ `Point` cannot be formatted with the default formatter|
Newtype Pattern
特性实现时有个orphan rule,即至少特性或者类型其中一方必须是这个crate的。这个规则可以用newtype pattern 规避掉。我们可以建立一个tuple struct,里面只有一个元素,就是我们想要实现新特性的那个类型。这样一个tuple struct就成为了wrapper type。这样就可以在实际使用的时候通过实例化Wrapper type来使用新特性。
use std::fmt; struct Wrapper(Vec<String>); impl fmt::Display for Wrapper { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "[{}]", self.0.join(", ")) } } fn main() { let w = Wrapper(vec![String::from("hello"), String::from("world")]); println!("w = {}", w); }
此外,newtype还可以对实现进行一定程度上的封装抽象化,只暴露Wrapper type的一些公共接口,把inner type的一些私有API封装起来。此外,例如可以struct People(HashMap<i32, String>),用户就可以少知道inner type的细节。
Type Aliases
type Kilometers = i32;
type Thunk = Box<dyn Fn() + Send + 'static>; let f: Thunk = Box::new(|| println!("hi"));
Never type
Rust有个特殊的类型,名为!,这个是作为一个空类型,主要用来放在return type的地方,提示函数不返回任何值的。
此外,可以用!解释continue。continue可以认为是返回了!。编译器在推测返回值具体类型的时候,会忽略!即continue对应的分支,去看其他的返回值可能。此外,panic!,print!宏可以认为都是返回了!。
Dynamically Sized Types
一般的类型可以认为实现了Sized trait,有固定长度的含空间大小。
对长度不定的trait object,我们必须用dyn关键字,如&dyn traitA, Box<dyn traitA>等。
泛型一般来说也是用T: Sized,如果要用未知大小的类型,需要使用?Sized
fn generic<T: ?Sized>(t: &T) { // --snip-- }