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}