每日一 R「18」类型系统进阶(二)
今天的课程主题是实战中的 trait object 使用方法。在运行时,我们只关注类型表现出某个 trait 的行为,而不关心其具体类型时就可以使用 trait object,用法时 &dyn T 或 Box<dyn T>。Trait object 是一个固定大小的胖指针,同时指向具体类型值和 vtable。
从本质上讲,trait object 和 泛型一样,是 Rust 实现多态的一种方式。Trait object 也是一种延迟绑定,可以推迟决策到运行时。Trait object 使用的是动态分配,因此在获得较高灵活性的同时,也失去了部分执行效率。
01-trait object 作为函数参数
Trait object 作为函数参数时的用法如下(基于动态分发):
02-trait object 作为函数返回值
Trait object 也可作为函数的返回值:
上例中返回值的类型是 Result<T, E>,其中 T 为在堆上分配的 trait object,E 为 KvError。
03-trait object 作为数据结构的域
Trait object 除了在函数中使用,还可作为数据结构的域:
其实上述结构也可通过泛型实现,例如:
但是,相比于 trait object,使用泛型有两个主要的缺点:
如果泛型个数比较多,代码就会比较臃肿,可读性降低;
任何使用数据结构的地方,都必须带着泛型以及泛型参数的约束,写起来不方便。
综上,使用 trait object 虽然会损失部分执行性能(由动态分配导致),但会提高代码可读性,而且代码只有一份实现。
在数据结构中使用 trait object 还有一个典型的场景:闭包。例如:
本节课程链接《24|类型系统:如何在实战中使用trait object?》
历史文章推荐
版权声明: 本文为 InfoQ 作者【Samson】的原创文章。
原文链接:【http://xie.infoq.cn/article/f611ebca938b337e30dc09f39】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论