简体   繁体   English

如何为结构体的引用实现 Add trait?

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

I made a two element Vector struct and I want to overload the + operator.我做了一个两元素的Vector结构,我想重载+运算符。

I made all my functions and methods take references, rather than values, and I want the + operator to work the same way.我让我的所有函数和方法都接受引用,而不是值,并且我希望+运算符以相同的方式工作。

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

Depending on which variation I try, I either get lifetime problems or type mismatches.根据我尝试的变化,我要么遇到生命周期问题,要么出现类型不匹配。 Specifically, the &self argument seems to not get treated as the right type.具体来说, &self参数似乎没有被视为正确的类型。

I have seen examples with template arguments on impl as well as Add , but they just result in different errors.我在implAdd上看到了带有模板参数的示例,但它们只会导致不同的错误。

I found How can an operator be overloaded for different RHS types and return values?我发现如何为不同的 RHS 类型和返回值重载运算符? but the code in the answer doesn't work even if I put a use std::ops::Mul;但是即使我use std::ops::Mul;答案中的代码也不起作用use std::ops::Mul; at the top.在顶部。

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

I won't accept "you only have two fields, why use a reference" as an answer;我不会接受“你只有两个字段,为什么要使用参考”作为答案; what if I wanted a 100 element struct?如果我想要一个 100 个元素的结构怎么办? I will accept an answer that demonstrates that even with a large struct I should be passing by value, if that is the case (I don't think it is, though.) I am interested in knowing a good rule of thumb for struct size and passing by value vs struct, but that is not the current question.我会接受一个答案,该答案表明即使使用大型结构,我也应该按值传递,如果是这样的话(不过我不认为是这样。)我有兴趣了解结构大小的良好经验法则并通过值与结构传递,但这不是当前的问题。

You need to implement Add on &Vector rather than on Vector .您需要在&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,
        }
    }
}

In its definition, Add::add always takes self by value.在其定义中, Add::add总是按值获取self But references are types like any other 1 , so they can implement traits too.但是引用和任何其他1一样是类型,因此它们也可以实现特征。 When a trait is implemented on a reference type, the type of self is a reference;在引用类型上实现 trait 时, self的类型是引用; the reference is passed by value.引用是按值传递的。 Normally, passing by value in Rust implies transferring ownership, but when references are passed by value, they're simply copied (or reborrowed/moved if it's a mutable reference), and that doesn't transfer ownership of the referent (because a reference doesn't own its referent in the first place).通常,在 Rust 中按值传递意味着转移所有权,但是当引用按值传递时,它们只是被复制(或者,如果它是可变引用,则重新借用/移动),并且不会转移所指对象的所有权(因为引用首先不拥有其所指对象)。 Considering all this, it makes sense for Add::add (and many other operators) to take self by value: if you need to take ownership of the operands, you can implement Add on structs/enums directly, and if you don't, you can implement Add on references.考虑到所有这些, Add::add (和许多其他运算符)按值获取self是有意义的:如果您需要获取操作数的所有权,您可以直接在结构/枚举上实现Add ,如果您不这样做,您可以在引用上实现Add

Here, self is of type &'a Vector , because that's the type we're implementing Add on.在这里, self&'a Vector类型,因为这是我们实现Add on 的类型。

Note that I also specified the RHS type parameter with a different lifetime to emphasize the fact that the lifetimes of the two input parameters are unrelated.请注意,我还指定了具有不同生命周期的RHS类型参数,以强调两个输入参数的生命周期无关的事实。


1 Actually, reference types are special in that you can implement traits for references to types defined in your crate (ie if you're allowed to implement a trait for T , then you're also allowed to implement it for &T ). 1实际上,引用类型的特殊之处在于您可以为在 crate 中定义的类型的引用实现特征(即,如果您被允许为T实现一个特征,那么您也可以为&T实现它)。 &mut T and Box<T> have the same behavior, but that's not true in general for U<T> where U is not defined in the same crate. &mut TBox<T>具有相同的行为,但对于U<T> ,通常情况并非如此,其中U未在同一个板条箱中定义。

If you want to support all scenarios, you must support all the combinations:如果要支持所有场景,必须支持所有组合:

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

In rust proper, this was done through an internal macro .在 rust 中,这是通过内部宏完成的

Luckily, there is a rust crate, impl_ops , that also offers a macro to write that boilerplate for us: the crate offers the impl_op_ex!幸运的是,有一个Rust crate, impl_ops ,它还提供了一个宏来为我们编写样板:这个 crate 提供了impl_op_ex! macro, which generates all the combinations.宏,它生成所有组合。

Here is their sample:这是他们的样本:

#[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);
}

Even better, they have a impl_op_ex_commutative!更好的是,他们有一个impl_op_ex_commutative! that'll also generate the operators with the parameters reversed if your operator happens to be commutative.如果您的运算符碰巧是可交换的,这也会生成参数反转的运算符。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在引用而不是引用值上调用特征方法? - How do I call a trait method on a reference and not the referenced value? 如何初始化对Option的可变引用的struct字段? - How do I initialize a struct field which is a mutable reference to an Option? 如何在MongoDB中手动添加引用? - How do I manually add a reference in MongoDB? 为什么特质实现不编译为结构,但编译为对结构的引用? - Why doesn't a trait implementation compile for a struct, but it compiles for a reference to the struct? 如何通过引用分配Swift结构? - How can I assign a Swift struct by reference? 何时使用引用或框包含在结构中实现特征的字段? - When to use a reference or a box to have a field that implements a trait in a struct? 什么时候我不应该实现引用该特征的实现者的特征? - When should I not implement a trait for references to implementors of that trait? 如何将程序集添加到Visual Studio项目并引用它? - How do I add an assembly to a Visual Studio project and reference it? 如何添加对项目的引用以避免额外下载 - How do I add a reference to a project to avoid extra downloads 为什么在泛型函数中对特征的引用必须实现`Sized`? - Why does a reference to a trait in a generic function have to implement `Sized`?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM