【问题标题】:How can I use an object as a parameter of its own method in Rust?如何在 Rust 中使用对象作为其自身方法的参数?
【发布时间】:2019-03-02 19:06:14
【问题描述】:

我为 Rust 中的一个简单结构编写了以下代码。这只是一个例子,没有太多真正的逻辑:

struct Vec2 {
    x: f32,
    y: f32,
}

impl Vec2 {
    fn multiply(&mut self, other: &Vec2) {
        self.x *= other.x;
        self.y *= other.y;
    }
}

我可以创建简单的向量并将一个向量与另一个向量相乘,但是当我尝试将一个向量与自身相乘时遇到了一个问题:编译器抱怨我不能将该向量借用为可变的,因为它也被借用为不可变。

fn main() {
    let mut vec = Vec2 { x: 2.0, y: 2.3 };
    vec.multiply(&vec);
}
error[E0502]: cannot borrow `vec` as mutable because it is also borrowed as immutable
  --> src/main.rs:15:5
   |
15 |     vec.multiply(&vec);
   |     ^^^^--------^----^
   |     |   |        |
   |     |   |        immutable borrow occurs here
   |     |   immutable borrow later used by call
   |     mutable borrow occurs here

这是有道理的,但是将这样的向量与自身相乘的正确方法是什么?更重要的是:对于一般情况下,我需要使用自己的方法修改结构,并使用相同的结构作为参数。

【问题讨论】:

  • 在这种特殊情况下,最简单的解决方案是为Vec2 派生Copy,并通过值而不是通过引用来接受other

标签: methods rust borrow-checker mutability


【解决方案1】:

我想你已经明白了这一点,但你现在所拥有的东西不起作用的原因是,一个值不能与不可变借用同时被可变借用。要按原样执行该方法,您需要同时使用可变借用(&mut self 形式)和不可变借用(other: &Vec2 形式)。由于您的方法应该适用于 Vec2 的任何两个成员,因此您将始终有两个单独的借用:编译器无法推断出单个借用适用于将向量自身相乘的情况。

至于您的问题,您有多种选择,具体取决于您尝试执行的操作的详细信息。

选项 1:克隆

只需将#[derive(Clone)] 添加到Vec2 的定义中,您就可以使用clone 方法克隆该类型的元素。

#[derive(Clone)]
struct Vec2 {
    x: f32,
    y: f32,
}

impl Vec2 {
    fn multiply(&mut self, other: &Vec2) {
        self.x *= other.x;
        self.y *= other.y;
    }
}

fn main() {
    let mut vec = Vec2 { x: 2.0, y: 2.3 };
    vec.multiply(&vec.clone());
}

选项 2:复制

如果您的类型如此简单(只有两个浮点数),那么您也可以合理地派生Copy。然后,该类型的元素在馈送到函数时被简单地复制,而不需要引用。这意味着我们应该将Vec2::multiply 的签名更改为将other 简单地视为Vec2,而不是&Vec2(这不是绝对必要的,但是对于Copy 类型而言,使用指针通常效率较低) .

#[derive(Copy, Clone)]
struct Vec2 {
    x: f32,
    y: f32,
}

impl Vec2 {
    fn multiply(&mut self, other: Vec2) {
        self.x *= other.x;
        self.y *= other.y;
    }
}

fn main() {
    let mut vec = Vec2 { x: 2.0, y: 2.3 };
    vec.multiply(vec);
}

选项 3:专用方法

您可以有一个单独的方法,称为 multiply_selfsquare(取决于您的语义),它只需要 &mut self。在使用自身修改结构的一般情况下,这可能是您最好的选择。

struct Vec2 {
    x: f32,
    y: f32,
}

impl Vec2 {
    fn multiply_self(&mut self) {
        self.x *= self.x;
        self.y *= self.y;
    }
}

fn main() {
    let mut vec = Vec2 { x: 2.0, y: 2.3 };
    vec.multiply_self();
}

选项 4:返回一个新值

您可以有一个不可变地采用self 而是返回一个新的Vec2 的方法。然后你可以做vec = vec.multiply(&vec)

struct Vec2 {
    x: f32,
    y: f32,
}

impl Vec2 {
    fn multiply(&self, other: &Vec2) -> Vec2 {
        Vec2 {
            x: self.x * other.x,
            y: self.y * other.y,
        }
    }
}

fn main() {
    let mut vec = Vec2 { x: 2.0, y: 2.3 };
    vec = vec.multiply(&vec)
}

可能有很多其他方法可以做到这一点,但这是在这个简单的案例中想到的。如果您分享更多关于您一般尝试做什么的详细信息,我可能会想出更多。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-11-02
    • 2013-04-17
    • 1970-01-01
    • 1970-01-01
    • 2016-11-28
    • 2019-02-02
    • 1970-01-01
    • 2018-01-12
    相关资源
    最近更新 更多