2016-06-18 67 views
0

C++允許使用類子類型,這非常方便,因爲您可以使用派生類爲基類實現的函數。 Rust似乎沒有這樣的東西。該功能似乎在某些時候已經可用,但自此之後已被刪除。這在Rust中是不可能的嗎?如果是這樣,有沒有計劃有這個功能?Rust中的子類型

我想要做的就是確定從另一個結構,這在C++看起來像繼承結構:

struct Base { 
    int x; 
    int y; 
    void foo(int x, int y) { this->x = x; this->y = y; } 
} 

struct Derived: public Base { 
    ... 
} 

void main() { 
    Derived d; 
    d.foo(); 
} 

的方式我看它,在防鏽你必須寫,爲了這樣的事情使可用於所有「衍生」結構相同的功能:

struct Base<T> { 
    x: i32, 
    y: i32, 
    derived: T 
} 
impl<T> Base<T> { 
    fn foo(&mut self, x: i32, y: i32) { 
     self.x = x; 
     self.y = y; 
    } 
} 

我覺得做一個impl<T> for Base<T>會產生一噸的相同功能的拷貝,所以成分是不是一個真正的選擇。

我應該指出,上面的實現被選中的原因很簡單,它允許一個更安全的upcasting版本,無論如何我都需要這樣做。

+8

鐵鏽甚至沒有類。它爲運行時多態性使用基於特徵的系統。你可以添加一個你想要的東西的例子(也許用C++編寫的工作代碼)?然後我們可以告訴你如何將它寫入Rust :) –

+0

編輯原始文章更清晰。 – eugene2k

+2

作爲一名C++程序員,我覺得需要指出的是,指導原則是**優先於繼承構成**,而您的示例通常被認爲是反模式。繼承應該只用於重寫行爲(又名'虛擬'函數),從非多態類繼承通常是一個錯誤(混合兩個概念:是 - 關係和代碼重用)。幸運的是,Rust具有後見之明,在Rust中沒有繼承:) –

回答

2

使用組合而不是繼承。

struct Base { 
    x: u8, 
    y: u8, 
} 

impl Base { 
    fn foo(&mut self, x: u8, y: u8) { 
     self.x = x; 
     self.y = y; 
    } 
} 

struct Derived { 
    base: Base, 
} 

impl Derived { 
    fn foo(&mut self, x: u8, y: u8) { 
     self.base.foo(x, y); 
    } 
} 

fn main() { 
    let mut d = Derived { base: Base { x: 1, y: 3 } }; 
    d.foo(5, 6); 
} 

可能做製作成分那樣容易鍵盤繼承上,雖然一個更好的工作。有a RFC旨在提供一些更好的,以及以前的討論1,2

我認爲做一個impl<T> for Base<T>會產生大量相同功能的副本,所以組合並不是真正的選擇。

我不確定這個語法試圖顯示什麼,因爲Base沒有泛型類型。確實,對於每個具體的類型參數集,泛型都是單態,但我沒有看到/知道與C++有什麼不同。我認爲Rust版本會稍微輕一些,因爲你不能從Derived上傳到Base,所以編譯器不必維護這些不變量。

所有這些都假定有一些代碼可以重用。在很多情況下,您最好編寫一個界面,該界面在Rust中用traits表示。您可以結合使用這兩種方法 - 將小部分可重用代碼作爲組件提取出來,將它們集合在一起成爲聚合,並實現聚合類型的特徵。

+0

當你有多個派生類時,可以簡化它。如果你編寫一個通用的'struct Base '並添加一個'derived:T',那麼你就不必在你想要實現的每個派生結構中編寫'base:Base'。然後,您可以使用'impl Base '爲派生結構添加impls。我正在那樣做。問題是當你有一百個派生結構時會發生什麼?根據我對每個Derived結構的理解,編譯器將生成一個新函數,它執行相同的操作。 – eugene2k

+0

我再次澄清了這篇文章。希望它現在更有意義。 – eugene2k

0

我想答案是,在Rust中沒有子類型。分型解決的問題類型不能總是通過組合,泛型或特徵來解決。問題是known to the devs並提供瞭解決方案,但尚未確定。