trait就是一种功能,比如,有一个自定义的mytrait trait, 你可以在mytrait里说要实现任何功能(函数);同时你也可以为所需要的对象进行实现(即impl mytrait for any)(注:Copy trait特殊除外)。-------这是你的权利
但是,你不一定可以说,让实现mytrait功能形成特定对象(&mytrait)。-------你要承担一些义务
即对象安全所尽的义务。
从某个角度上讲,trait的可以分安全对象的trait,和非安全对象的trait,只有安全对象的trait,才有资格带上&。比如,你看不到&Clone或Box < Clone>
此前,碰到这种情况,代码如下:
#[derive(Clone)]
struct Trade(i32);
trait Bet{
fn bet(&self);
}
trait Test :Bet
fn test(&self);
}
impl Test for Trade{
fn test(&self){}
}
impl Trade{
fn default(&self) -> Vec<Box<dyn Test>>{
let mut v = Vec::new();
let trade = Trade(0);
v.push(Box::new(trade) as Box<dyn Test > );
v
}
}
这个是没有问题的。
但是,如果把Test改一下:
trait Test :Send
fn test(&self);
}
但Clone,Sized加上去都会报错。
1、Send+ Sync与Clone、Sized
#[derive(Clone)]
struct Trade(i32);
trait Bet{
fn bet(&self);
}
trait Test :Send+Sync //而不是Clone和Sized
fn test(&self);
}
impl Test for Trade{
fn test(&self){}
}
impl Trade{
fn default(&self) -> Vec<Box<dyn Test>>{
let mut v = Vec::new();
let trade = Trade(0);
v.push(Box::new(trade) as Box<dyn Test > );
v
}
}
但是,如果是,Sized、Clone组合,仍会报错。
2、object-safe trait 问题
trait object 它不仅包括指向真实对象的指针,还包括一个指向虚函数表的指针。因此,并不是所有的trait都能作为trait对象使用的。
只有 对象安全(object safe)的 trait 才可以组成 trait 对象。trait的方法满足以下两条要求才是对象安全的:
(1)返回值类型不为 Self
(2)方法没有任何泛型类型参数
典型的安全对象trait的案例:Clone trait Clone是非对象安全的,所以不能作为trait对象。
trait Clone{
fn clone(&self) ->Self
}
因为clone()返回Self类型,不符合上面的规则(1)。所以尽管你对你实现Clone
trait的对象调用clone()方法,但是,你不能把&Clone带到任何的地方去。
3、关于trait与泛型,struct结合, 一个更进一步的例子
例子: 有一个Manager,Empylee,他们都共同实现Earn(赚钱的能力) trait。
里面有一个问题:当抽像变成具体时,可能在编译时无法确定对象大小。
pub trait Earn: Send + Sync {
fn earn(&self);
}
#[derive(Debug, Clone)]
struct Manager<T>
where
T: Earn,
{
people: Vec<Box<T>>,
}
trait Run {
fn run(&self);
}
#[derive(Debug, Clone)]
struct Employee(i32);
impl Earn for Employee {
fn earn(&self) {}
}
impl<T: Earn> Earn for Manager<T> {
fn earn(&self) {}
}
//
impl<T: Earn> Manager<T> {
fn make_employees(&self) -> Vec<Box<dyn Earn>> {
let mut v = Vec::new();
let e = Employee(0);
println!("e:{:?}", e);
v.push(Box::new(e) as Box<dyn Earn>); // as Box<dyn Earn>);
v
}
fn make_managers(&self) -> Vec<Box<dyn Earn>> {
let mut v = Vec::new();
{
// problem :把抽像变具体
let e = self.make_employees();
let manager = Manager{ people: e };
}
// ok
let e = Employee(0);
let manager = Manager {
people: vec![Box::new(e)],
};
v.push(Box::new(manager) as Box<dyn Earn>);
v
}
}
fn main() {
// let t = Trade(0);
// let v = t.to_vec();
println!("ok");
}
关于trait更进一步的了解,可以参考,写得不错:
https://zhuanlan.zhihu.com/p/127365605
4、一个有意思的库: DynClone
在github上,DynClone好象想做些不同的事。
https://github.com/dtolnay/dyn-clone
如:
use dyn_clone::DynClone;
trait MyTrait: DynClone {
fn recite(&self);
}
impl MyTrait for String {
fn recite(&self) {
println!("{} ♫", self);
}
}
fn main() {
let line = "The slithy structs did gyre and gimble the namespace";
// Build a trait object holding a String.
// This requires String to implement MyTrait and std::clone::Clone.
let x: Box<dyn MyTrait> = Box::new(String::from(line));
x.recite();
// The type of x2 is a Box<dyn MyTrait> cloned from x.
let x2 = dyn_clone::clone_box(&*x);
x2.recite();
}