簡體   English   中英

如何為結構體的引用實現 Add trait?

[英]How do I implement the Add trait for a reference to a struct?

我做了一個兩元素的Vector結構,我想重載+運算符。

我讓我的所有函數和方法都接受引用,而不是值,並且我希望+運算符以相同的方式工作。

impl Add for Vector {
    fn add(&self, other: &Vector) -> Vector {
        Vector {
            x: self.x + other.x,
            y: self.y + other.y,
        }
    }
}

根據我嘗試的變化,我要么遇到生命周期問題,要么出現類型不匹配。 具體來說, &self參數似乎沒有被視為正確的類型。

我在implAdd上看到了帶有模板參數的示例,但它們只會導致不同的錯誤。

我發現如何為不同的 RHS 類型和返回值重載運算符? 但是即使我use std::ops::Mul;答案中的代碼也不起作用use std::ops::Mul; 在頂部。

我每晚使用 rustc 1.0.0 (ed530d7a3 2015-01-16 22:41:16 +0000)

我不會接受“你只有兩個字段,為什么要使用參考”作為答案; 如果我想要一個 100 個元素的結構怎么辦? 我會接受一個答案,該答案表明即使使用大型結構,我也應該按值傳遞,如果是這樣的話(不過我不認為是這樣。)我有興趣了解結構大小的良好經驗法則並通過值與結構傳遞,但這不是當前的問題。

您需要在&Vector而不是在Vector上實現Add

impl<'a, 'b> Add<&'b Vector> for &'a Vector {
    type Output = Vector;

    fn add(self, other: &'b Vector) -> Vector {
        Vector {
            x: self.x + other.x,
            y: self.y + other.y,
        }
    }
}

在其定義中, Add::add總是按值獲取self 但是引用和任何其他1一樣是類型,因此它們也可以實現特征。 在引用類型上實現 trait 時, self的類型是引用; 引用是按值傳遞的。 通常,在 Rust 中按值傳遞意味着轉移所有權,但是當引用按值傳遞時,它們只是被復制(或者,如果它是可變引用,則重新借用/移動),並且不會轉移所指對象的所有權(因為引用首先不擁有其所指對象)。 考慮到所有這些, Add::add (和許多其他運算符)按值獲取self是有意義的:如果您需要獲取操作數的所有權,您可以直接在結構/枚舉上實現Add ,如果您不這樣做,您可以在引用上實現Add

在這里, self&'a Vector類型,因為這是我們實現Add on 的類型。

請注意,我還指定了具有不同生命周期的RHS類型參數,以強調兩個輸入參數的生命周期無關的事實。


1實際上,引用類型的特殊之處在於您可以為在 crate 中定義的類型的引用實現特征(即,如果您被允許為T實現一個特征,那么您也可以為&T實現它)。 &mut TBox<T>具有相同的行為,但對於U<T> ,通常情況並非如此,其中U未在同一個板條箱中定義。

如果要支持所有場景,必須支持所有組合:

  • &T op U
  • 頂部&U
  • &T 操作 &U
  • 托普

在 rust 中,這是通過內部宏完成的

幸運的是,有一個Rust crate, impl_ops ,它還提供了一個宏來為我們編寫樣板:這個 crate 提供了impl_op_ex! 宏,它生成所有組合。

這是他們的樣本:

#[macro_use] extern crate impl_ops;
use std::ops;

impl_op_ex!(+ |a: &DonkeyKong, b: &DonkeyKong| -> i32 { a.bananas + b.bananas });

fn main() {
    let total_bananas = &DonkeyKong::new(2) + &DonkeyKong::new(4);
    assert_eq!(6, total_bananas);
    let total_bananas = &DonkeyKong::new(2) + DonkeyKong::new(4);
    assert_eq!(6, total_bananas);
    let total_bananas = DonkeyKong::new(2) + &DonkeyKong::new(4);
    assert_eq!(6, total_bananas);
    let total_bananas = DonkeyKong::new(2) + DonkeyKong::new(4);
    assert_eq!(6, total_bananas);
}

更好的是,他們有一個impl_op_ex_commutative! 如果您的運算符碰巧是可交換的,這也會生成參數反轉的運算符。

暫無
暫無

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

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