于 Rust 1.76 稳定的 trait upcasting coercion
由于在 Rust 1.76 发布前夕,trait upcasting coercion 突然发现了健全性问题,因此该特性已被取消稳定,目前还没有下一步的稳定计划。
先提出一个问题,在 Rust 中如何把一个 &dyn MyTrait
转换为 &MyStruct
?
1
2
3
4
5
6
7
8
9
10
11
trait MyTrait {}
struct Foo;
struct Bar;
impl MyTrait for Foo {}
impl MyTrait for Bar {}
fn rtti(obj: &dyn MyTrait) {
// How to convert `obj` to `&Foo` or `&Bar`
}
很自然地,我们可以想到借助 Any
,rust 在 dyn Any
类型上实现了 is()
和 downcast_ref()
可以很好地帮助我们在运行时获取类型信息。
然而,在 Rust 1.75.0 及之前,想要从 &dyn MyTrait
中获取 &dyn Any
并不是一件简单的事情,你需要在 MyTrait
中专门添加一个方法 as_any()
将自身转换为 &dyn Any
,并且不厌其烦地在每一个 impl MyTrait for S
中复制粘贴一份其实现:
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
use std::any::Any;
trait MyTrait {
fn as_any(&self) -> &dyn Any;
}
struct Foo;
struct Bar;
impl MyTrait for Foo {
fn as_any(&self) -> &dyn Any {
self
}
}
impl MyTrait for Bar {
fn as_any(&self) -> &dyn Any {
self
}
}
fn rtti(obj: &dyn MyTrait) {
let any = obj.as_any();
if any.is::<Foo>() {
let _ref: &Foo = any.downcast_ref().unwrap();
} else if any.is::<Bar>() {
let _ref: &Bar = any.downcast_ref().unwrap();
}
}
而在 Rust 1.76.0 中,trait upcasting coercion 迎来了稳定。什么是 trait upcasting coercion 呢?简单的说,对于 trait A: B
,可以直接将 &dyn A
强制为 &dyn B
,这意味着,我们只需要让 trait MyTrait: Any
,即可实现从 &dyn MyTrait
到 &dyn Any
的转换了:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
use std::any::Any;
trait MyTrait: Any {}
struct Foo;
struct Bar;
impl MyTrait for Foo {}
impl MyTrait for Bar {}
fn rtti(obj: &dyn MyTrait) {
let any = obj as &dyn Any;
if any.is::<Foo>() {
let _ref: &Foo = any.downcast_ref().unwrap();
} else if any.is::<Bar>() {
let _ref: &Bar = any.downcast_ref().unwrap();
}
}
本文由作者按照 CC BY 4.0 进行授权