【Rust投稿】捋捋 Rust 中的 impl Trait 和 dyn Trait
发布日期:2021-05-20 06:54:51 浏览次数:18 分类:精选文章

本文共 1264 字,大约阅读时间需要 4 分钟。

返回多种类型的函数在 Rust 中的实现问题解答

写 Rust 程序时,如果函数需要根据不同条件返回不同的类型,这在静态类型语言中总是面临一个挑战。对于 Rust 而言,这个问题得到了巧妙的解决,特别是在多态类型和 trait 对象的引入后。

问题背景

假设我们有一个函数 some_fn,它需要根据输入参数返回 ButtonTextView 中的某一种。初始想法是直接返回其中一种类型。但是很快就发现问题:Rust 的静态类型系统不允许函数返回两个或多个不同的类型,因为这会导致返回值不一致。

解决办法:装箱 Box

为了让函数返回多种类型,我尝试使用 Box 智能指针。这使得返回一个大指针,以便一个指针可以指向不同的子类型。通过返回 Box<Button>Box<TableViewCell>,一个 Box<dyn View>(使用 dyn 时在 Rust 2018 及以上版本)可以包裹所有这些类型。

这解决了编译器关于返回类型一致性的问题,同时表明返回值的大小是固定的(因为 Box 对内存有固定的分配)。

Rust 2018 及以上的变化

在原来的代码中,使用 Box<View> 会导致编译器在排除错误时报告:使用 trait 对象而没有显式 dyn 被弃用。

根据 Rust 2018 的更新,Box<View> 已经不推荐使用,应该改为 Box<dyn View>。这表明:

  • dyn 关键字强制编译器知道我想使用 trait 对象类型。
  • 这样做避免了混淆,因为用户不会误以为只是一个普通的类型。

impldyn 的区别

在 Rust 中,impldyn 分别关联于静态分发和动态分发。

  • impl Trait 表示静态分发。编译器会在编译期为特定的类型生成适合该类型的实现,这提高性能,但函数无法返回多种类型。

  • dyn Trait 表示动态分发。返回一个 Box<dyn Thing>,所以函数可以返回任何实现 Trait 的类型。运行时使用 trait 对象的 vtable 来决定如何调用方法,带来灵活性,但有额外的运行期开销。

这样,选择 dyn 的原因实际上是语义上的清晰解决问题:明确表示希望返回 trait 对象类型,而不是静态类型。

变通的语义问题

impl Traitdyn Trait 的区别在于静态与动态分发。这反映出 Rust 的高效和灵活。当静态分发足以满足性能需求时,使用它更合适,因为它避免了运行期动态调用带来的开销。

然而,在需要动态行为或多态性时,dyn 必不可少。

总结

在 Rust 中,impldyn 关键字赋予了函数返回多种类型的可能性。在静态分发下,函数不能返回多种子类型,所以需要使用 dyn 来实现动态分发,返回 Box<dyn Trait>。这保证了高效的性能和灵活性,同时清晰地表达了代码意图,避免了语义混淆。

理解这两个关键字的区别和用法,可以显著提升对 Rust 汇编代码和内在机制的理解,从而更好地应对复杂的多态性需求。

上一篇:Rust异步浅谈
下一篇:【Rust投稿】从零实现消息中间件(6)-CLIENT

发表评论

最新留言

逛到本站,mark一下
[***.202.152.39]2025年04月30日 00时30分03秒