重载Add-operator而不复制操作数

Mon*_*nth 5 rust

我正在Rust中编写一个应用程序,它必须集中使用向量算法,我偶然发现了为结构类型设计运算符重载的问题.

所以我有一个这样的矢量结构:

struct Vector3d {
    pub x: f64,
    pub y: f64,
    pub z: f64,
}
Run Code Online (Sandbox Code Playgroud)

我希望能够写出类似的东西:

let x = Vector3d {x:  1.0, y: 0.0, z: 0.0};
let y = Vector3d {x: -1.0, y: 0.0, z: 0.0};

let u = x + y;
Run Code Online (Sandbox Code Playgroud)

据我所知,有三种不同的方法:

  1. 直接实施std::ops::Add特质Vector3d.这有效,但这个特征的方法签名是:

    fn add(self, other: Vector3d)
    
    Run Code Online (Sandbox Code Playgroud)

所以它会在使用后使它的参数无效(因为它会移动它们),这在我的情况下是不可取的,因为许多矢量将用在多个表达式中.

  1. 实现Add特征Vector3d并实现Copy特征.这是有效的,但我觉得如果因为Vector3d它不是一个轻量级的东西(至少24字节)可以快速复制,特别是当有很多调用算术函数时.

  2. 实现Add对参考文献Vector3d,如建议在这里.这是有效的,但为了应用运算符,我将不得不写

    let u = &x + &y;
    
    Run Code Online (Sandbox Code Playgroud)

我不喜欢这种符号,因为它看起来并不完全像数学等价物u = x + y.

我不确定哪种变体是最佳的.所以,问题是:有没有办法以这样的方式重载'+'运算符

  1. 它接受其参数作为引用,而不是复制或移动它们;
  2. 它允许写u = x + y而不是u = &x + &y

Luk*_*odt 6

有没有办法以这种方式重载'+'运算符

  1. 它接受其参数作为引用,而不是复制或移动它们;
  2. 它允许写u = x + y而不是u = &x + &y

,没有办法做到这一点.Rust非常重视显性,并且几乎不会在类型之间自动转换.

但是,解决问题的方法很简单:只是#[derive(Copy)].我可以向你保证,24字节不是很多.如今,计算机喜欢立即处理大量数据而不是处理少量数据.


除此之外,Copy并不是关于复制/克隆的性能开销:

只需复制位即可复制的类型(即memcpy).

后来的文件中:

一般来说,如果你的类型可以实现Copy,它应该.

您的类型Vector3d可以通过复制位来复制,因此它应该实现Copy(通过#[derive()]它).

性能开销是一个不同的问题.如果你有一个可以(并因此确实)实现Copy的类型,但你仍然认为类型太大(再次:24个字节不是!),你应该以他们接受引用的方式设计你的所有方法(它不是这很简单;请阅读Matthieu的评论).这还包括Addimpl.如果你想通过引用将某些东西传递给函数,程序员应该明确地写它.这就是Rust的哲学无论如何都会说的.

  • *你应该以接受引用的方式设计所有方法*=>我首先检查IR.编译器不按值传递大类型,它们实际上将引用传递给临时副本(因为寄存器),如果被调用的函数是内联的,优化器可能只是忽略临时副本并直接引用原始副本.在这种情况下,当您在语义上通过副本传递时,在程序集级别,您将通过不可变引用传递. (3认同)