簡體   English   中英

Rust - 相同類型的不同行為

[英]Rust - Same Type different behaviour

就我的理解而言,泛型允許在不同類型之間共享相同的行為。 為實例,

trait Bird {}

struct BirdFly {}

impl Bird for BirdFly  {
   pub fn fly() -> can fly
}

struct BirdCanntFly {}

impl Bird for BirdCanntFly{
   pub fn fly() -> cannt fly
}

let birds = vec![
    Box::new(BirdFly{}),        // allow this bird to fly, for instance
    Box::new(BirdCanntFly{}),   // dont't allow this bird to fly
];

我的問題是相反的,即是否有可能讓相同的類型采取不同的行為(沒有 ifs、enums 或 Box)。在這個例子中,在兩種類型(BirdFly 和 BirdCanntFly)維度相同,只是行為不同。 就像是:

struct Bird {
   fly: // associate different behavior
}

let birds = vec![
    Bird{ fly: some_fly_behavior },      // allow this bird to fly, for instance
    Bird{ fly: another_fly_behavior },   // dont't allow this bird to fly
];

birds[0].fly();
birds[1].fly();

如果 fly 收到相同的參數並返回相同的類型,我看不出問題的原因。 此外,通過這種方式,我可以擺脫矢量內的 Box。 特別是因為我可能在向量中有數百萬個元素並且被多次迭代訪問,這樣我就可以避免開銷。 謝謝您的幫助!

您可以將函數指針存儲在struct Bird並添加一個輔助方法來獲得您想要的語法。

struct Bird {
    name: String,
    fly_impl: fn(&Bird) -> (),
}

impl Bird {
    fn new(name: String, fly_impl: fn(&Bird) -> ()) -> Bird {
        Bird { name, fly_impl }
    }

    fn fly(self: &Bird) {
        (self.fly_impl)(self)
    }
}

fn behavior1(b: &Bird) {
    println!("{} behavior1", b.name);
}

fn behavior2(b: &Bird) {
    println!("{} behavior2", b.name);
}

fn main() {
    let captured_variable = 10;
    let birds = vec![
        Bird::new("Bird1".into(), behavior1),
        Bird::new("Bird2".into(), behavior2),
        Bird::new("Bird3".into(), |b| println!("{} lambda", b.name)),
        /*Bird::new("Bird4".into(), |b| {
            println!("{} lambda with {}", b.name, captured_variable)
        }),*/
    ];
    (birds[0].fly_impl)(&birds[0]);
    for bird in birds {
        bird.fly();
    }
}

不要將fntrait Fn混淆。 前者只允許函數和非捕獲 lambdas 並且具有固定大小。 后者允許任意大小的任意捕獲,因此需要一些像Box間接。 兩者都在調用時進行動態調度。

請注意Bird3的行為如何由非捕獲 lambda 指定,這是允許的。 但是,如果您嘗試取消對Bird4的注釋,該示例將無法編譯,因為其所需的行為是捕獲 lambda,它通常會變得任意大,並且我們已經禁止Box es 和其他間接方式。

我對 Rust 的了解不夠多,無法告訴您是否有更類似於 Rust 的解決方案。 但是,您的情況非常具體:

  • 您有一個任意可擴展的Bird層次結構。 否則enum更適合。
  • 但是,此層次結構中的所有Bird都具有完全相同的一組字段和trait支持。 否則,您必須通過Box<dyn Bird>使用trait和標准動態調度。
  • 您不希望為單個Bird分配堆。 否則,您可以使用trait和標准動態調度。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM