Impl and Dyn on Rust
12 November, 2020
我们先来看这样一段代码:
impl View for Button { ... }
impl View for Text { ... }
我们看到Button
和Text
都实现了View
属性, 抽象是一种不错的设计程序的方法, 帮助我们透明化的使用外部提供的API. 然后我们可能会下意识的写出下面的代码:
/// 这种代码实际上会让人感到疑惑. View究竟是个特性还是一个对象.
/// 这里的View是一个类型, 所以我们需要写成 `impl View`.
/// 不过`impl View` 不能用于多个trait实现的返回. 但是可以作为入参.
pub fn something() -> View {
if ... {
Button { ... }
} else {
Text { ... }
}
}
这段代码无法通过编译, 原因就是返回值View
需要在编译器确认大小. 我们需要把它装成一个胖指针.
pub fn something() -> Box<View> {...}
嗯,这样就好很多. 但是编译器会爆种, 提出一个警告, 希望你把Box<View>
改为Box<dyn View>
.
这又是什么意思?
dyn
是动态的缩写, 意义其实很明显. 使用dyn
修饰的类型, 会在程序执行期动态分发. 会有一定的RUNTIME开销.
pub fn something() -> Box<dyn View> {...}
现在我们把代码改成这样, 好多了.
接下来说说impl
, 这个语法是个语法糖其实.怎么个语法糖呢?
fn something<T: View>(v: T) { ... }
// ------------- 用 impl 之后 ------------------
fn something(v: impl View) { ... }
真的就这么简单.
第二次说一遍, 这种T(泛型)
写法在入参可以这么做, 但是返回值不行. 除非你的返回值只返回一个T
实现. 两种以上请重载 (我乱说的,rust可能不支持)
或者使用dyn
.