sui_rust/ch02/
s5_trait_and_generic.rs

1//! 第二章:Rust核心概念
2//! 2.4 trait 和 泛型
3//!
4//!
5
6/**
7
8   # 概念介绍
9
10   ### trait 四种作用
11
12   - 接口 (interface)
13   - 类型标记(Mark)
14   - 泛型限定(trait bound)
15   - 抽象类型(trait object)
16
17
18  ### 静态分发(单态化 - Monomorphized)
19
20   ```rust
21   use std::string::ToString;
22
23   fn print<T: ToString>(v: T) {
24       println!("{}", v.to_string());
25   }
26   ```
27
28   或 `impl Trait`语法
29
30   ```rust
31   use std::string::ToString;
32
33   #[inline(never)]
34   fn print(v: &impl ToString) {
35       println!("{}", v.to_string());
36   }
37   ```
38
39   使用 `impl Trait` 解决问题:
40
41
42   ```rust
43   // error codes:
44
45   use std::fmt::Display;
46
47   fn main() {
48       println!("{}", make_value(0));
49       println!("{}", make_value(1));
50   }
51
52   fn make_value<T: Display>(index: usize) -> T {
53       match index {
54           0 => "Hello, World",
55           1 => "Hello, World (1)",
56           _ => panic!(),
57       }
58   }
59
60   ```
61
62   修正:
63
64   ```
65   use std::fmt::Display;
66
67   fn make_value(index: usize) -> impl Display {
68       match index {
69           0 => "Hello, World",
70           1 => "Hello, World (1)",
71           _ => panic!(),
72       }
73   }
74
75   ```
76
77   `impl Trait` 生命周期相关:
78
79   ```rust
80
81   // error
82   fn make_debug<T>(_: T) -> impl std::fmt::Debug + 'static{
83       42u8
84   }
85
86   // fn make_debug<'a, T: 'static>(_: &'a T) -> impl std::fmt::Debug + 'static{
87   //     42u8
88   // }
89
90   fn test() -> impl std::fmt::Debug {
91       let value = "value".to_string();
92       make_debug(&value)
93   }
94   ```
95
96  实际案例 - 模版模式:[https://github.com/actix/actix-extras/tree/master/actix-web-httpauth](https://github.com/actix/actix-extras/tree/master/actix-web-httpauth)
97
98
99  # trait 一致性
100
101   trait 和 类型 必须有一个在本地。
102
103
104
105*/
106pub fn trait_concept() {
107    println!("trait 概念")
108}
109
110/**
111
112
113# 动态分发
114
115    ### trait 对象
116
117    用泛型模拟 Class
118
119    ```rust
120
121    #![allow(unused)]
122
123    use core::any::{Any,TypeId};
124    use std::sync::Arc;
125
126    /// Class definition
127    struct Class {
128        /// The name of the class
129        name: String,
130        /// The corresponding Rust type
131        type_id: TypeId,
132    }
133
134    impl Class {
135        /// Create a new class definition for the type `T`
136        fn new<T: 'static>() -> Self {
137            Self {
138                name: std::any::type_name::<T>().to_string(),
139                type_id: TypeId::of::<T>(),
140            }
141        }
142    }
143
144    /// An instance of a class
145    struct Instance {
146        inner: Arc<dyn Any>, // `Arc` because we don't need/want mutability
147    }
148
149    impl Instance {
150        /// Construct a new `Instance` from a type that
151        /// implements `Any` (i.e. any sized type).
152        fn new(obj: impl Any) -> Self {
153            Self {
154                inner: Arc::new(obj)
155            }
156        }
157    }
158
159    impl Instance {
160        /// Check whether this is an instance of the provided class
161        fn instance_of(&self, class: &Class) -> bool {
162            // self.inner.type_id() == class.type_id
163            self.inner.as_ref().type_id() == class.type_id
164        }
165    }
166
167    struct Foo {}
168    struct Bar {}
169
170    fn main(){
171
172
173        let foo_class: Class = Class::new::<Foo>();
174        let bar_class: Class = Class::new::<Bar>();
175        let foo_instance: Instance = Instance::new(Foo {});
176
177        assert!(foo_instance.instance_of(&foo_class));
178        assert!(!foo_instance.instance_of(&bar_class));
179    }
180    ```
181
182*/
183pub fn trait_dyn_dispatch() {
184    println!("trait 动态分发");
185}
186
187/**
188
189# trait 对象本质
190
191
192示例 1:
193
194```rust
195    struct CloningLab {
196        subjects: Vec<Box<Mammal>>,
197        // subjects: Vec<Box<Mammal + Clone>>,
198    }
199
200    trait Mammal {
201        fn walk(&self);
202        fn run(&self);
203    }
204
205    #[derive(Clone)]
206    struct Cat {
207        meow_factor: u8,
208        purr_factor: u8
209    }
210
211    impl Mammal for Cat {
212        fn walk(&self) {
213            println!("Cat::walk");
214        }
215        fn run(&self) {
216            println!("Cat::run")
217        }
218    }
219
220
221```
222
223示例2:
224
225```rust
226
227    #![allow(unused)]
228    #![feature(raw)]
229
230    use std::{mem, raw};
231
232    // an example trait
233    trait Foo {
234        fn bar(&self) -> i32;
235    }
236
237    impl Foo for i32 {
238        fn bar(&self) -> i32 {
239            *self + 1
240        }
241    }
242
243    fn main() {
244        let value: i32 = 123;
245
246        // let the compiler make a trait object
247        let object: &dyn Foo = &value;
248
249        // look at the raw representation
250        let raw_object: raw::TraitObject = unsafe { mem::transmute(object) };
251
252        // the data pointer is the address of `value`
253        assert_eq!(raw_object.data as *const i32, &value as *const _);
254
255        let other_value: i32 = 456;
256
257        // construct a new object, pointing to a different `i32`, being
258        // careful to use the `i32` vtable from `object`
259        let synthesized: &dyn Foo = unsafe {
260            mem::transmute(raw::TraitObject {
261                data: &other_value as *const _ as *mut (),
262                vtable: raw_object.vtable,
263            })
264        };
265
266        // it should work just as if we had constructed a trait object out of
267        // `other_value` directly
268        assert_eq!(synthesized.bar(), 457);
269    }
270
271```
272
273正常 trait Object 布局图:
274
275```text
276
277                                                           cat's vtable
278Cat Layout                     Trait Object
279+------------+              +--------------+             +---------------+
280|            |              |              |             |               |
281|            |              |              |     +-----> | drop pointer  |
282| meow_factor|              |              |     |       |    size       |
283|            +<--------------+data pointer |     |       |    align      |
284| purr_factor|              |              |     |       |               |
285|            |              | vtable pointer-----+       | run fn pointer|
286|            |              |              |             |walk fn pointer|
287|            |              |              |             |               |
288+------------+              +--------------+             |               |
289                                                         |               |
290                                                         |               |
291                                                         |               |
292                                                         +---------------+
293
294```
295
296假设:trait Mammal + Clone 布局图:
297
298注意:非法
299
300```text
301
302                                                                  Mammal
303                                                           cat's vtable
304Cat Layout                     Trait Object
305+------------+              +--------------+             +---------------+
306|            |              |              |             |               |
307|            |              |              |     +-----> | drop pointer  |
308| meow_factor|              |              |     |       |    size       |
309|            +<--------------+data pointer |     |       |    align      |
310| purr_factor|              |              |     |       |               |
311|            |              | vtable pointer-----+       | run fn pointer|
312|            |              |              |             |walk fn pointer|
313|            |              |              +-----+       |               |
314+------------+              +--------------+     |       |               |
315                                                 |       |               |
316                                                 |       |               |
317                                                 |       |               |
318                                                 |       +---------------+
319                                                 |
320                                                 |
321                                                 |           Clone Vtable
322                                                 |
323                                                 +-----> +--------------+
324                                                         |              |
325                                                         | drop pointe  |
326                                                         |              |
327                                                         | size         |
328                                                         | align        |
329                                                         |              |
330                                                         |  clone       |
331                                                         |  fn pointer  |
332                                                         |              |
333                                                         +--------------+
334
335
336```
337
338    假设:trait 继承(`trait MammalClone: Mammal+Clone`)布局图:
339
340    注意:非法
341
342```text
343
344                                                            MammalClone
345                                                           cat's vtable
346Cat Layout                     Trait Object
347+------------+              +--------------+             +-----------------+
348|            |              |              |             |                 |
349|            |              |              |     +-----> | drop pointer    |
350| meow_factor|              |              |     |       |    size         |
351|            +<--------------+data pointer |     |       |    align        |
352| purr_factor|              |              |     |       |                 |
353|            |              | vtable pointer-----+       | run fn pointer  |
354|            |              |              |             |walk fn pointer  |
355|            |              |              |             |                 |
356+------------+              +--------------+             |clone fn pointer |
357                                                         |                 |
358                                                         |                 |
359                                                         |                 |
360                                                         +-----------------+
361
362 ```
363
364
365*/
366pub fn trait_object() {
367    println!("trait 动态分发");
368}
369
370/**
371
372#  对象安全
373
374
375
376### 对象安全
377
378    一个 trait 如果能实现自己,就认为它是对象安全的
379
380为什么必须是对象安全呢?
381
382trait对象,在运行时已经擦除了类型信息,要通过虚表调用相应的方法。不像静态分发那样,trait对象不是为每个类型都实现trait的方法,而是只实现一个副本(自动为其实现自身),结合虚函数去调用。
383
384现在想一个问题: 假如那个类型没有实现这个方法怎么办?
385实际上,会有很多种情况下,会出现这个问题。运行时确定的类型和方法应该合法的,保证trait对象在运行时可以安全地调用相关的方法。
386
387比如trait里有泛型函数。这就搞的很复杂了,可能运行时无法确定该调用哪个函数。反正是各种情况吧。所以,为了避免出现这种问题,官方引入了对象安全的概念。
388实际上就是引入了一系列的规则,也就是上面列出的那些。编译器根据这些规则,在编译期判断一个你写的trait对象,是不是合法的。
389
390比如:trait对象其实在内部维护两个表:safe_vtable和nonself_vtable,标记有where Self: Sized的会被归类到nonself_vtable,也就是说,不会被trait对象调用。
391这样的话,方法标记有where Self: Sized的trait对象自然是安全的,因为这表示 这个方法 只能为 Self: Sized 都类型实现,是有条件的,所以在运行时有可能存在无效(万一有不是Sized的类型调用,就没有该方法)调用。
392
393如果是合法的,则代表了,这个trait对象在运行时调用方法应该是没问题的。
394不会出现没有实现,或者不知道该调用哪个的情况。
395这就是对象安全的概念。它和内存安全并无直接关系。
396所以,对象安全的本质就是为了让trait对象可以安全地调用相应的方法。
397
398如果没有Sized的限定,那么就会很容易写出无用的类型。比如 Box,它用做trait对象即便会编译,但是不能用它做任何事情(后面有演示代码)。
399对于更复杂的trait,往往就没有这么明显了,只有在做了大量繁重的工作之后可能会突然发现某个trait对象无法正常调用方法。
400所以,为trait增加Sized限定,然后编译器自动为该trait实现自身,就可以在编译期准确排除无效的trait对象。
401这就是对象安全。需要注意的是,对象安全和内存安全并无直接的关联,它只是保证trait对象在运行时可以安全准确地调用相关的方法。
402
403```rust
404    trait StarkFamily {
405        fn last_name(&self)  -> &'static str;
406        fn totem(&self) -> &'static str;
407    }
408
409    trait TullyFamily {
410        fn territory(&self) -> &'static str;
411    }
412
413    trait Children {
414        fn new(first_name: &'static str) -> Self where Self: Sized;
415        fn first_name(&self) -> &'static str;
416    }
417
418    impl StarkFamily for Children {
419        fn last_name(&self)  -> &'static str{
420            "Stark"
421        }
422
423        fn totem(&self)  -> &'static str{
424            "Wolf"
425        }
426    }
427
428    impl TullyFamily for Children {
429        fn territory(&self)  -> &'static str{
430            "Riverrun City"
431        }
432    }
433
434    struct People{
435        first_name: &'static str
436    }
437
438    impl Children for People {
439        fn new(first_name: &'static str) -> Self where Self: Sized{
440            println!("hello : {} Stark ", first_name);
441            People{first_name: first_name}
442        }
443
444        fn first_name(&self) -> &'static str{
445            self.first_name
446        }
447    }
448
449    fn full_name(person: Box<dyn Children>) {
450        println!(" --- Winter is coming, the lone {:?} dies, the pack lives ---", person.totem());
451        let full = format!("{} {}", person.first_name(), person.last_name() );
452        println!("I'm {:?}", full );
453        println!("My Mother come from {:?}", person.territory());
454    }
455
456    fn main() {
457        let sansa = People::new("Sansa");
458        let aray = People::new("Aray");
459
460        let starks: Box<dyn Children> = Box::new(sansa);
461        full_name(starks);
462
463        let starks: Box<dyn Children> = Box::new(aray);
464        full_name(starks);
465    }
466
467```
468
469
470对象安全规则 Rust 源码:[https://github.com/rust-lang/rust/blob/941343e0871dd04ea774e8cee7755461b144ef29/compiler/rustc_middle/src/traits/mod.rs#L643](https://github.com/rust-lang/rust/blob/941343e0871dd04ea774e8cee7755461b144ef29/compiler/rustc_middle/src/traits/mod.rs#L643)
471
472
473*/
474pub fn object_safety() {
475    println!("对象安全本质");
476}
477
478/**
479
480# 当不能实现 trait 对象当时候该如何?
481
4821. 将其转化为 Enum
483
484trait 对象代码:
485
486```rust
487    trait KnobControl {
488        fn set_position(&mut self, value: f64);
489        fn get_value(&self) -> f64;
490    }
491
492    struct LinearKnob {
493        position: f64,
494    }
495
496    struct LogarithmicKnob {
497        position: f64,
498    }
499
500    impl KnobControl for LinearKnob {
501        fn set_position(&mut self, value: f64) {
502            self.position = value;
503        }
504
505        fn get_value(&self) -> f64 {
506            self.position
507        }
508    }
509
510    impl KnobControl for LogarithmicKnob {
511        fn set_position(&mut self, value: f64) {
512            self.position = value;
513        }
514
515        fn get_value(&self) -> f64 {
516            (self.position + 1.).log2()
517        }
518    }
519
520    fn main() {
521        let v: Vec<Box<dyn KnobControl>> = vec![
522            //set the knobs
523        ];
524
525        //use the knobs
526    }
527```
528
529转为 enum:
530
531```rust
532    enum Knob {
533        Linear(LinearKnob),
534        Logarithmic(LogarithmicKnob),
535    }
536
537    impl KnobControl for Knob {
538        fn set_position(&mut self, value: f64) {
539            match self {
540                Knob::Linear(inner_knob) => inner_knob.set_position(value),
541                Knob::Logarithmic(inner_knob) => inner_knob.set_position(value),
542            }
543        }
544
545        fn get_value(&self) -> f64 {
546            match self {
547                Knob::Linear(inner_knob) => inner_knob.get_value(),
548                Knob::Logarithmic(inner_knob) => inner_knob.get_value(),
549            }
550        }
551    }
552```
553
554当 trait 不满足对象安全规则的时候,也可以用 Enum 代替。
555
556```rust
557#![allow(unused)]
558
559use core::ops::Add;
560
561trait KnobControl<T: Add + Add<Output = T> + Copy> {
562    fn set_position(&mut self, value: T);
563    fn get_value(&self, p: T) -> T;
564}
565
566struct LinearKnob<T: Add+ Add<Output = T> + Copy> {
567    position: T,
568}
569
570struct LogarithmicKnob<T: Add+ Add<Output = T> + Copy>  {
571    position: T,
572}
573
574impl<T: Add+ Add<Output = T> + Copy> KnobControl<T> for LinearKnob<T> {
575    fn set_position(&mut self, value: T) {
576        self.position = value;
577    }
578
579    fn get_value(&self, p: T) -> T {
580        self.position + p
581    }
582}
583
584impl<T: Add+ Add<Output = T> + Copy> KnobControl<T> for LogarithmicKnob<T> {
585    fn set_position(&mut self, value: T) {
586        self.position = value;
587    }
588
589    fn get_value(&self, p: T) -> T {
590        (self.position + p)
591    }
592}
593
594fn main() {
595    enum Knob<T: Add+ Add<Output = T> + Copy> {
596        Linear(LinearKnob<T>),
597        Logarithmic(LogarithmicKnob<T>),
598    }
599
600    impl<T: Add+ Add<Output = T> + Copy> KnobControl<T> for Knob<T> {
601        fn set_position(&mut self, value: T) {
602            match self {
603                Knob::Linear(inner_knob) => inner_knob.set_position(value),
604                Knob::Logarithmic(inner_knob) => inner_knob.set_position(value),
605            }
606        }
607
608        fn get_value(&self, p: T) -> T {
609            match self {
610                Knob::Linear(inner_knob) => inner_knob.get_value(p),
611                Knob::Logarithmic(inner_knob) => inner_knob.get_value(p),
612            }
613        }
614    }
615}
616
617
618```
619
620
6212. 利用 “魔法” ,相当于加一层代理 : 参考:[https://github.com/dtolnay/erased-serde/blob/master/explanation/main.rs](https://github.com/dtolnay/erased-serde/blob/master/explanation/main.rs)
622
623*/
624pub fn trait_object_to_enum() {
625    println!("blanket impls");
626}
627
628/**
629
630# Overlapping blanket impls
631
632当前 Rust 不支持  `trait `为 同一个类型覆盖实现:
633
634```rust
635    trait Blanket {
636        fn blanket(&self) -> &'static str;
637    }
638
639    impl Blanket for u8 {
640        fn blanket(&self) -> &'static str {
641            "impl1"
642        }
643    }
644
645    // Compilation fails at that point
646    impl Blanket for u8 {
647        fn blanket(&self) -> &'static str {
648            "impl2"
649        }
650    }
651
652    fn main() {
653        // If compilation succeeded, what would be printed?
654        println!("{}", 0u8.blanket());
655    }
656
657```
658
659再比如泛型:
660
661```rust
662    impl <T: ToString> Blanket for T { ... }
663
664    // Compilation fails at that point
665    impl <T: Clone> Blanket for T { ...}
666
667```
668
669以上是 Rust 不允许的。
670
671虽然特化功能也逐渐开始支持,但不足以解决上面这种存在`trait`实现“竞争”的情况。
672
673一个解决方案是:
674
675```rust
676    trait Blanket<I> {
677        fn blanket(&self) -> &'static str;
678    }
679
680    impl Blanket<u8> for u8 {
681        fn blanket(&self) -> &'static str {
682            "u8"
683        }
684    }
685
686    impl<T: ToString> Blanket<&ToString> for T {
687        fn blanket(&self) -> &'static str {
688            "ToString"
689        }
690    }
691
692    trait CloneBlanket {}
693
694    impl<T: Clone> Blanket<&CloneBlanket> for T {
695        fn blanket(&self) -> &'static str {
696            "Clone"
697        }
698    }
699
700    trait TryIntoBlanket<T> {
701        type Error;
702    }
703
704    impl<T, E, U> Blanket<&TryIntoBlanket<T, Error = E>> for U
705    where
706        U: TryInto<T, Error = E>,
707    {
708        fn blanket(&self) -> &'static str {
709            "try_into"
710        }
711    }
712
713    impl<T: ToString> Blanket<&ToString> for T {
714        fn blanket(&self) -> &'static str {
715            "to_string"
716        }
717    }
718
719    impl<T: AsRef<U>, U: ?Sized> Blanket<&AsRef<U>> for T {
720        fn blanket(&self) -> &'static str {
721            "as_ref"
722        }
723    }
724
725```
726
727方案参考:https://codesandwich.github.io/overlapping_blanket_impls/
728
729
730
731*/
732pub fn blanket_impls() {
733    println!("blanket impls");
734}
735
736/**
737
738    ### 对象安全规则里,为什么需要 `Self: Sized`
739
740    思考:什么情况下需要 `Self: Sized` ?
741
742    ```rust
743
744    trait WithConstructor {
745        fn build(param: usize) -> Self where Self: Sized;
746
747        fn new() -> Self where Self: Sized {
748            Self::build(0)
749        }
750
751
752        fn t(&self){
753            println!("T");
754        }
755
756        fn p(&self){
757            self.t();
758            println!("hello");
759        }
760    }
761
762    struct A;
763
764    impl WithConstructor for A {
765        fn build(param: usize) -> Self{
766            A
767        }
768
769    }
770
771    fn main(){
772        let a : &WithConstructor = &A ;
773    }
774    ```
775
776    示例 2:
777
778    ```rust
779
780    trait Test {
781        fn foo(self);
782
783        fn works(self: Box<Self>){
784            println!("hello Trait");
785        }
786
787        fn fails(self: Box<Self>)
788        where Self: Sized
789        {
790            self.foo()
791        }
792    }
793
794    struct Concrete;
795
796    impl Concrete {
797        fn hello(&self){
798            println!("hello");
799        }
800    }
801
802    struct Bar;
803
804    impl Bar {
805        fn hello(&self){
806            println!("hello Bar");
807        }
808    }
809
810    impl Test for Bar {
811        fn foo(self) { () }
812        fn works(self: Box<Self>) { self.hello()}
813    }
814
815    impl Test for Concrete {
816        fn foo(self) { () }
817        fn works(self: Box<Self>) { self.hello()}
818    }
819
820    fn main() {
821        let concrete: Box<dyn Test> = Box::new(Concrete);
822        concrete.works();
823        let concrete: Box<dyn Test> = Box::new(Bar);
824        concrete.works();
825        // concrete.fails(); // compilation error
826    }
827
828    ```
829
830    结论:
831    1. `Self: Sized` 为了保证 trait 默认实现内部的 Self 调用都是合法的。
832    2. 防止 函数体内包含了 Self 的默认实现混入虚表。因为虚表内 Self 无法确定。
833
834    ### Sized  vs  ?Sized
835
836    ```rust
837    trait WithConstructor {
838        fn build(param: usize) -> Self where Self: ?Sized;
839
840        fn new() -> Self where Self: ?Sized {
841            Self::build(0)
842        }
843    }
844    ```
845
846*/
847pub fn trait_self_sized_bound() {
848    println!("trait object vs Self: Sized");
849}