为了账号安全,请及时绑定邮箱和手机立即绑定

为什么Rust不支持特征对象向上转换?

为什么Rust不支持特征对象向上转换?

为什么Rust不支持特征对象向上转换?鉴于此代码: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在这样或那样的方法。检查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,所有Rust vtable都包含指向第一个字段中的析构函数,大小和对齐的指针,并且子引用vtable在引用supertrait方法时不会复制它们,也不会使用对supertrait vtables的间接引用。他们只是逐字地拥有方法指针的副本而没有别的。鉴于这种设计,很容易理解为什么这不起作用。需要在运行时构建一个新的vtable,它可能存在于堆栈中,这并不是一个优雅(或最佳)的解决方案。当然,有一些解决方法,比如在界面中添加显式的upcast方法,但这需要相当多的样板(或宏观狂热)才能正常工作。现在,问题是 - 为什么不能以某种方式实现特征对象向上转换?比如,在subtrait的vtable中添加指向supertrait的vtable的指针。目前,Rust的动态调度似乎不满足Liskov替换原则,这是面向对象设计的一个非常基本的原则。当然你可以使用静态调度,这在Rust中使用确实非常优雅,但它很容易导致代码膨胀,这有时比计算性能更重要 - 比如在嵌入式系统上,而Rust开发人员声称支持这样的用例。语言。此外,在许多情况下,您可以成功使用一个非纯粹面向对象的模型,这似乎是Rust的功能设计所鼓励的。尽管如此,Rust支持许多有用的OO模式......那么为什么不使用LSP呢?有谁知道这种设计的理由?
查看完整描述

3 回答

?
杨魅力

TA贡献1811条经验 获得超5个赞


截至2017年6月,这种“次级特征胁迫”(或“超级特质胁迫”)的状态如下:

  • 一个公认的RFC #0401提到这是强制的一部分。所以这种转换应该是隐含的。

    coerce_inner(T)= U其中T是一个子特征U;

  • 但是,这尚未实施。还有一个相应的问题#18600

还有一个重复的问题#5665。那里的评论解释了什么阻止了这一点的实施。

  • 基本上,问题是如何为超级特征推导vtable。vtables的当前布局如下(在x86-64情况下):

    + ----- + ------------------------------- +| 0-7 |指向“滴胶”功能|+ ----- + ------------------------------- +| 8-15 |数据大小|+ ----- + ------------------------------- +| 16-23 |数据对齐|+ ----- + ------------------------------- +| 24- |自我和超人的方法|+ ----- + ------------------------------- +

    它不包含超级特征的vtable作为子序列。我们至少要对vtables进行一些调整。

  • 当然有一些方法可以缓解这个问题,但很多都有不同的优点/缺点!当有钻石继承时,一个有利于vtable尺寸。另一个应该更快。

他们准备了一份看起来井井有条的RFC草案,但在那之后它们看起来就像消失了(2016年11月)。


查看完整回答
反对 回复 2019-07-25
  • 3 回答
  • 0 关注
  • 775 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信