10|再探trait:带类型参数的trait及trait object
trait 上带类型参数
- 深入了解
- 翻译
- 解释
- 总结
Rust中带类型参数的trait及trait object是本文的重点。文章深入探讨了类型参数在trait中的不同位置及其侧重意义,详细讲解了带类型参数的trait的定义和实现方式,以及在实现时对类型参数的约束和具体化。通过具体实例展示了带类型参数的trait的威力,以及在同一类型上实现同名方法参数类型的多种形态。此外,还介绍了带类型参数的trait的默认实现方式,并指出了初学者可能遇到的困难。文章还指出了关联类型的具化和类型参数的默认类型指定的区别。最后,文章介绍了trait object的概念,通过具体示例和对比分析,清晰地展现了带类型参数的trait和关联类型的区别,为读者提供了深入的技术视角。整体而言,本文全面介绍了带类型参数的trait及其相关知识,为读者提供了深入的了解和学习指导。文章还讨论了trait object、impl trait,以及使用枚举对类型进行聚合这三种方式之间的区别。类型系统(类型+ trait)是Rust的大脑,读者可以通过本文的内容多加练习,熟悉它的形式,掌握它的用法。
《Rust 语言从入门到实战》,新⼈⾸单¥59
全部留言(15)
- 最新
- 精选
- 哄哄rust生命周期的独特设计,导致了该语言需要设计一些处理方式应对特殊情况,比如生命周期的标注(主要是给编译器进行代码处理时的提示)。事实上,我们在日常开发中应该避免一些陷入复杂情况的方式:比如,传入参数都用引用(borrow),传出结果都应该是owner。rust也为我们提供了处理各种情况的工具。所以,一般来说,我们应该在传入参数的时候用&dyn T,传出结果用Box<dyn T>。
作者回复: 真不错👍
2023-11-10归属地:北京214 - 鸠摩智&dyn TraitA没有所有权,而Box<dyn TraitA>有所有权。
作者回复: 对的
2023-11-10归属地:江苏4 - 哄哄关联类型之所以要单独设计,因为编译器可以通过输入判断具体类型,而无法推断出输出类型,所以,输出的类型需要明确指定
作者回复: 思考方式很棒!
2023-11-10归属地:北京24 - -最后安全的trait object听的似懂非懂,为什么是安全的,为什么是不安全的?希望具体讲下原因
作者回复: 这里面的设计原理确实比较dirty了。我先给出三篇文章参考,你可以深入下去研究:https://rustcc.cn/article?id=e80a98d7-4adb-4d39-bf0a-4e079bcb1835 https://segmentfault.com/a/1190000022104780 https://rust-lang.github.io/rfcs/0255-object-safety.html
2023-11-10归属地:北京42 - superggn笔记: trait 可以带泛型 generics trait 关联类型 associated type 跟泛型类似, 但必须在 impl 的时候就具化 泛型就随便啥时候具化都行了 `fn doit(i: u32) -> impl TraitA` => 某一种实现了 TraitA 的类型 `fn doit(i: u32) -> Box<dyn TraitA>` => 多种实现了 TraitA 的类型 前两次刷 rbe 和 rustbook 的时候都没反应过来为啥叫 trait object, 看这课终于明白了, 原来 trait obejct 指的是 typeOuter 的 OuterSizedObj, 然后这个 OuterSizedObj 里面可以包裹各种实现了 traitA 的 type 对应 obj 还是得多刷点儿资料, 多看对于同一概念的不同表达, 明白的快
作者回复: 真棒!
2023-12-15归属地:北京1 - superggn思考题: &dyn traitA 和 Box<dyn traitA> 严格来说都是指向 actual object 的指针, 只不过 `&` 叫做引用, `Box` 叫做智能指针, 这俩都是固定大小的, 所以都能用在 trait object 区别: &dyn traitA 是一个不拿所有权的指针 => 所以经常用在参数里 Box<dyn traitA> 是拥有内部数据所有权的指针 => 所以经常用在返回值里, 参数里应该也能用
作者回复: 对的。👍
2023-12-15归属地:北京1 - 李诗涛老师老师,我有一个问题。就是您说impl trait目前有两个使用的地方,分别是函数入参和返回。但给出的例子里,在入参使用impl trait时编译器会自动展开。但在出返回值使用impl trait时,若是返回了不同的类型却会报错。这是怎么理解?
作者回复: 你可以再仔细理解一下impl trait 放在入参位置的示例和放在返回值位置的区别。它们实际都是编译期展开的应用,但是逻辑会有区别。由于返回值的if是运行时才有值来判断,因此在每次调用实例时,它无法在编译期推导出准确的返回值类型。
2024-02-07归属地:上海 - 小可爱(`へ´*)ノ基础部分非常详细,建议老师可以深入讲一下trait object的内存相关知识,以及trait object会丢失本身类型信息这些注意点。
作者回复: 好滴, 记下了,后面会持续输出。
2023-12-28归属地:四川 - -Hedon🍭思考题:&dyn TraitA 是借用,Box<dyn TraitA> 会转移所有权。 通过下面的程序可以测试出来: fn doit3(t1: &dyn TraitA, t2: Box<dyn TraitA>) { println!("{:?}", t1); println!("{:?}", t2) } fn main() { let a = AType; let b = BType; doit3(&a, Box::new(b)); println!("{:?}", a); println!("{:?}", b); } 输出: error[E0382]: borrow of moved value: `b` --> examples/trait_object.rs:29:22 | 26 | let b = BType; | - move occurs because `b` has type `BType`, which does not implement the `Copy` trait 27 | doit3(&a, Box::new(b)); | - value moved here 28 | println!("{:?}", a); 29 | println!("{:?}", b); | ^ value borrowed here after move
作者回复: 👍👍
2023-11-21归属地:湖北 - 老大不要在 trait 里面定义构造函数,比如 new 这种返回 Self 的关联函数。你可以发现,确实在整个 Rust 生态中都没有将构造函数定义在 trait 中的习惯。 这句话,在上面的例子中 确实有在trait中定义了new函数返回self的。怎么就感觉有冲突呢?
作者回复: 观察得很细致,上面的例子主要是为了展现可能出现的写法。后面的说明加入了object safty的因素,以及社区的约定,所以看起来好像不一致,实际是一致的。
2023-11-21归属地:河南