oop – 为什么Rust不支持trait对象upcasting?

栏目: 编程语言 · Rust · 发布时间: 5年前

内容简介:http://stackoverflow.com/questions/28632968/why-doesnt-rust-support-trait-object-upcasting

给出这个代码:

trait Base {
    fn a(&self);
    fn b(&self);
    fn c(&self);
    fn d(&self);
}

trait Derived : Base {
    fn e(&self);
    fn f(&self);
    fn g(&self);
}

struct S;

impl Derived for S {
    fn e(&self) {}
    fn f(&self) {}
    fn g(&self) {}
}

impl Base for S {
    fn a(&self) {}
    fn b(&self) {}
    fn c(&self) {}
    fn d(&self) {}
}

不幸的是,我不能将& Derived投入到& Base.我想知道为什么会这样,因为Derived vtable必须以某种方式引用Base方法.

那么检查LLVM IR显示如下:

@vtable4 = internal unnamed_addr constant {
    void (i8*)*,
    i64,
    i64,
    void (%struct.S*)*,
    void (%struct.S*)*,
    void (%struct.S*)*,
    void (%struct.S*)*
} {
    void (i8*)* @_ZN2i813glue_drop.98717h857b3af62872ffacE,
    i64 0,
    i64 1,
    void (%struct.S*)* @_ZN6S.Base1a20h57ba36716de00921jbaE,
    void (%struct.S*)* @_ZN6S.Base1b20h3d50ba92e362d050pbaE,
    void (%struct.S*)* @_ZN6S.Base1c20h794e6e72e0a45cc2vbaE,
    void (%struct.S*)* @_ZN6S.Base1d20hda31e564669a8cdaBbaE
}

@vtable26 = internal unnamed_addr constant {
    void (i8*)*,
    i64,
    i64,
    void (%struct.S*)*,
    void (%struct.S*)*,
    void (%struct.S*)*,
    void (%struct.S*)*,
    void (%struct.S*)*,
    void (%struct.S*)*,
    void (%struct.S*)*
} {
    void (i8*)* @_ZN2i813glue_drop.98717h857b3af62872ffacE,
    i64 0,
    i64 1,
    void (%struct.S*)* @_ZN9S.Derived1e20h9992ddd0854253d1WaaE,
    void (%struct.S*)* @_ZN9S.Derived1f20h849d0c78b0615f092aaE,
    void (%struct.S*)* @_ZN9S.Derived1g20hae95d0f1a38ed23b8aaE,
    void (%struct.S*)* @_ZN6S.Base1a20h57ba36716de00921jbaE,
    void (%struct.S*)* @_ZN6S.Base1b20h3d50ba92e362d050pbaE,
    void (%struct.S*)* @_ZN6S.Base1c20h794e6e72e0a45cc2vbaE,
    void (%struct.S*)* @_ZN6S.Base1d20hda31e564669a8cdaBbaE
}

所有Rust vtables在第一个字段中包含指向析构函数,大小和对齐的指针,并且在引用supertrait方法时,子项目不会重复它们,也不使用间接引用supertrait vtables.他们只是逐字地复制方法指针,没有别的.

鉴于这种设计,很容易理解为什么这不起作用.需要在运行时构建一个新的vtable,它可能位于堆栈上,而不是一个优雅(或最优)的解决方案.

有一些解决方法,当然,像添加显式的upcast方法到界面,但这需要相当多的样板(或宏狂风)才能正常工作.

现在的问题是 – 为什么它不能以某种方式实现,这样可以使特征对象上传?就像在超级桌上的超级桌上添加一个指针.现在,Rust的动态调度似乎不能满足 LSP ,这是面向对象设计的一个非常基本的原则.

当然,您可以使用静态调度,这在Rust中非常优雅,但是它容易导致代码膨胀,这有时比计算性能更重要 – 比如嵌入式系统,Rust开发人员声称支持这样的用例语言.此外,在许多情况下,您可以成功使用不是纯OO的模型,这似乎被Rust的功能设计所鼓励.仍然,Rust支持许多有用的OO模式…所以为什么不是LSP?

有没有人知道这样的设计的理由?

其实我觉得我有理由我发现了一种优雅的方法来增加对任何需要的特征的支持,而 程序员 也可以选择是否将该额外的vtable条目添加到特征中,或者不喜欢,这是一个类似的权衡C的虚拟与非虚拟方法:优雅和模型的正确性与性能.

代码可以实现如下:

trait Base : AsBase {
    ...
}

trait AsBase {
    fn as_base(&self) -> &Base;
}

impl<T: Base> AsBase for T {
    fn as_base(&self) -> &Base { self }
}

当然,可以添加一些额外的方法来投射&mut指针或者一个Box(添加一个T必须是一个静态类型的要求),但这是一个一般的想法.这允许安全和简单(虽然不是隐含的)每个派生类型的上传,没有每个派生类型的样板.

http://stackoverflow.com/questions/28632968/why-doesnt-rust-support-trait-object-upcasting


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

C程序设计(第四版)

C程序设计(第四版)

谭浩强 / 清华大学出版社 / 2010-6-1 / 33.00元

由谭浩强教授著、清华大学出版社出版的《C程序设计》是一本公认的学习C语言程序设计的经典教材。根据C语言的发展和计算机教学的需要,作者在《C程序设计(第三版)》的基础上进行了修订。 《C程序设计(第4版)》按照C语言的新标准C99进行介绍,所有程序都符合C99的规定,使编写程序更加规范;对C语言和程序设计的基本概念和要点讲解透彻,全面而深入;按照作者提出的“提出问题―解决问题―归纳分析”三部曲......一起来看看 《C程序设计(第四版)》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

html转js在线工具
html转js在线工具

html转js在线工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试