国外网站可以访问吗,南阳网站排名价格,seo排名方案,网页界面设计的原则有哪些特性#xff0c;也叫特质#xff0c;英文是trait。 trait是一种特殊的类型#xff0c;用于抽象某些方法。trait类似于其他编程语言中的接口#xff0c;但又有所不同。 trait定义了一组方法#xff0c;其他类型可以各自实现这个trait的方法#xff0c;从而形成多态。
一、…特性也叫特质英文是trait。 trait是一种特殊的类型用于抽象某些方法。trait类似于其他编程语言中的接口但又有所不同。 trait定义了一组方法其他类型可以各自实现这个trait的方法从而形成多态。
一、定义trait
一使用trait关键字 语法格式
trait trait_name{fn fn1(self);fn fn2(self);//...
}其中包含一组方法。 方法第一个参数必须是self。
例子
trait MyTrait {fn do_something(self);
}方法可以有默认实现如果其他类型实现trait时不覆盖这些方法将使用默认实现。 例子
trait MyTrait {fn do_something(self) {// 默认实现}
}二trait继承 trait可以继承其他trait 语法格式
trait trait_name: parent_trait_name{fn fn1(self);
}例子
trait Printable {fn print(self);
}
trait Debuggable: Printable {fn debug(self);
}Debuggable继承了Printable从而Debuggable包含了Printable中的方法。
多继承 例子
trait Paginate: Page PerPage { fn set_skip_page(self, num: i32){println!(Skip Page: {:?}, num);}
}三关联类型 关联类型是一个类型占位符。当实现trait时才指定具体类型。 在trait定义里使用type关键字。 语法格式
trait xx {type T;
}例子 标准库提供的Iterator trait有一个关联类型Item
pub trait Iterator {type Item;fn next(mut self) - OptionSelf::Item;
}
impl Iterator for Counter {type Item u32;fn next(mut self) - OptionSelf::Item {Item是一个类型占位符next方法返回OptionSelf::Item 类型的值。这个trait的实现者会指定Item的具体类型。
关联类型看起来像泛型都是在定义时不指定具体类型。那么为什么不直接使用泛型呢比如下面这样
pub trait IteratorT {fn next(mut self) - OptionT;
}区别在于当trait有泛型参数时一个类型可以多次实现这个trait每次为泛型参数指定不同的具体类型。比如IteratorString for CounterIteratori32 for CounterIteratoru32 for Counter。Counter有多个Iterator的实现。 接着当使用Counter的next方法时必须标明使用哪一个Iterator实现。比如Counter.nextString()Counter.nexti32()Counter.nextu32()。 通过关联类型则无需标注类型因为只能实现一次这个trait。只能有一个impl Iterator for Counter。当调用Counter的next时不必每次指定我们需要u32值的迭代器。
二、实现trait
一为某个类型实现trait 使用impl关键字。 语法格式
impl trait_name for type{fn fn1(self);fn fn2(self);//...
}例子
trait MyTrait {fn do_something(self);
}
struct MyStruct;
impl MyTrait for MyStruct {fn do_something(self) {// 实现方法逻辑}
}在上述例子中我们为MyStruct类型实现了MyTrait。
二在外部类型上实现外部trait 孤儿规则是指trait或类型处于当前crate时才可以在此类型上实现该trait。这意味着无法在外部类型上实现外部trait。一个绕开这个限制的方法是使用newtype模式。 newtype模式是使用元组结构体创建一个新类型这个元组结构体只有一个字段相当于对这个字段类型的封装。这样这个新类型就处于当前crate了就可以为这个新类型实现trait。Newtype是一个源自Haskell编程语言的概念。使用这个模式没有运行时性能消耗这个封装类型在编译时就被省略了。 例如想要在VecT 上实现Display因为Display trait和VecT 都定义于我们的crate之外所以无法这么做。可以创建一个包含VecT 的元组结构体接着为元组结构体实现Display并使用VecT 的值
use std::fmt;
struct Wrapper(VecString);
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);
}使用self.0来访问其内部的VecT因为Wrapper是元组结构体而VecT 是结构体总位于索引0的项。 因为Wrapper是一个新类型它没有内部类型的方法。如果希望新类型拥有其内部类型的每一个方法那么可以为新类型实现Deref trait并返回其内部类型。如果不希望新类型拥有所有内部类型的方法那么必须自行实现所需的方法。
三、使用trait
一trait作为函数的参数 trait可以作为函数的参数类型
例子
fn output(object: impl Descriptive) {println!({}, object.describe());
}任何实现了Descriptive的实例都可以作为这个函数的参数
例子
trait Drawable {fn draw(self);
}
fn draw_shape(shape: impl Drawable) {shape.draw();
}函数draw_shape它接受实现了Drawable的类型作为参数。
如果涉及多个特性可以用 符号表示例如
fn notify(item: impl Summary Display)二trait作为返回值 trait可以作为函数的返回值类型 格式如下
fn person() - impl Descriptive {//
}例子
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,}
}returns_summarizable函数返回某个实现了Summary的类型的实例。在这个例子中返回了一个 Tweet不过调用方并不知情。
特性做返回值所有返回支返回值类型必须完全一样 比如下面这个函数就是错误的 实例
fn some_function(bool bl) - impl Descriptive {if bl {return StructA {};} else {return StructB {};}
}