1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
/// # 抽象类型:Box(装箱)抽象类型 之 trait对象
///
/// Base usage:
///
/// ```
/// #[derive(Debug)]
/// struct Foo;
/// trait Bar {
///     fn baz(&self);
/// }
/// impl Bar for Foo {
///     fn baz(&self) { println!("{:?}", self) }
/// }
/// fn static_dispatch<T>(t: &T) where T:Bar {
///     t.baz();
/// }
/// fn dynamic_dispatch(t: &Bar) {
///     t.baz();
/// }
/// let foo = Foo;
/// static_dispatch(&foo);
/// dynamic_dispatch(&foo);
/// ```
pub fn trait_object() {
    #[derive(Debug)]
    struct Foo;
    trait Bar {
        fn baz(&self);
    }
    impl Bar for Foo {
        fn baz(&self) { println!("{:?}", self) }
    }
    fn static_dispatch<T>(t: &T) where T:Bar {
        t.baz();
    }
    fn dynamic_dispatch(t: &Bar) {
        t.baz();
    }
    let foo = Foo;
    static_dispatch(&foo);
    dynamic_dispatch(&foo);
}


/// # 抽象类型: impl Trait unbox存在类型 (Rust 2018)
///
/// Base usage: 重构第二章中trait的示例
///
/// ```
/// use std::fmt::Debug;
/// trait Fly {
///     fn fly(&self) -> bool;
/// }
/// #[derive(Debug)]
/// struct Duck;
/// #[derive(Debug)]
/// struct Pig;
/// impl Fly for Duck {
///     fn fly(&self) -> bool {
///         return true;
///     }
/// }
/// impl Fly for Pig {
///     fn fly(&self) -> bool {
///         return false;
///     }
/// }
/// fn fly_static(s: impl Fly+Debug) -> bool {
///     s.fly()
/// }
/// fn can_fly(s: impl Fly+Debug) -> impl Fly {
///     if s.fly(){
///         println!("{:?} can fly", s);
///     }else{
///         println!("{:?} can't fly", s);
///     }
///     s
/// }
/// fn dyn_can_fly(s: impl Fly+Debug+'static) -> Box<dyn Fly> {
///     if s.fly(){
///         println!("{:?} can fly", s);
///     }else{
///         println!("{:?} can't fly", s);
///     }
///     Box::new(s)
/// }
/// let pig = Pig;
/// assert_eq!(fly_static(pig), false);  // 静态分发
/// let pig = Pig;
/// can_fly(pig);     // 静态分发
/// let duck = Duck;
/// assert_eq!(fly_static(duck), true); // 静态分发
/// let duck = Duck;
/// can_fly(duck);      // 静态分发
/// let duck = Duck;
/// dyn_can_fly(duck);   // 动态分发
/// ```
///
/// Base usage: 错误示范
///
/// ```
/// use std::ops::Add;
/// // 以下多个参数的情况,虽然同时指定了impl Add<T, Output=T>类型,
/// // 但是它们并不是同一个类型,因为这是抽象类型。
/// // 所以编译会出错: mismatched types
/// fn sum<T>(a: impl Add<T, Output=T>, b: impl Add<T, Output=T>) -> T{
///     a + b
/// }
/// ```
///
/// Base usage: 正确
///
/// ```
/// use std::ops::Add;
/// // 只能用于单个参数
/// fn hello<T>(a: impl Add<T, Output=T>) -> impl Add<T, Output=T>{
///     a
/// }
/// ```
pub fn impl_trait(){
    use std::fmt::Debug;
    pub trait Fly {
        fn fly(&self) -> bool;
    }
    #[derive(Debug)]
    struct Duck;
    #[derive(Debug)]
    struct Pig;
    impl Fly for Duck {
        fn fly(&self) -> bool {
            return true;
        }
    }
    impl Fly for Pig {
        fn fly(&self) -> bool {
            return false;
        }
    }
    fn fly_static(s: impl Fly+Debug) -> bool {
        s.fly()
    }
    fn can_fly(s: impl Fly+Debug) -> impl Fly {
        if s.fly(){
            println!("{:?} can fly", s);
        }else{
            println!("{:?} can't fly", s);
        }
        s
    }
    fn dyn_can_fly(s: impl Fly+Debug+'static) -> Box<dyn Fly> {
        if s.fly(){
            println!("{:?} can fly", s);
        }else{
            println!("{:?} can't fly", s);
        }
        Box::new(s)
    }
    let pig = Pig;
    assert_eq!(fly_static(pig), false);
    let duck = Duck;
    assert_eq!(fly_static(duck), true);

    let pig = Pig;
    can_fly(pig);
    let duck = Duck;
    can_fly(duck);

    let duck = Duck;
    dyn_can_fly(duck);
}