為什么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條經驗 獲得超6個贊
截至2017年6月,這種“次級特征脅迫”(或“超級特質脅迫”)的狀態如下:
還有一個重復的問題#5665。那里的評論解釋了什么阻止了這一點的實施。
基本上,問題是如何為超級特征推導vtable。vtables的當前布局如下(在x86-64情況下):
+ ----- + ------------------------------- +| 0-7 |指向“滴膠”功能|+ ----- + ------------------------------- +| 8-15 |數據大小|+ ----- + ------------------------------- +| 16-23 |數據對齊|+ ----- + ------------------------------- +| 24- |自我和超人的方法|+ ----- + ------------------------------- +
它不包含超級特征的vtable作為子序列。我們至少要對vtables進行一些調整。
當然有一些方法可以緩解這個問題,但很多都有不同的優點/缺點!當有鉆石繼承時,一個有利于vtable尺寸。另一個應該更快。
他們準備了一份看起來井井有條的RFC草案,但在那之后它們看起來就像消失了(2016年11月)。
添加回答
舉報
0/150
提交
取消
