操作员按值超载会导致使用已移动的值 [英] Operator overloading by value results in use of moved value

查看:74
本文介绍了操作员按值超载会导致使用已移动的值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

编译以下使用运算符重载的Rust代码

use std::ops::{Add};

#[derive(Show)]
struct Point {
    x: int,
    y: int
}

impl Add for Point {
    type Output = Point;

    fn add(self, other: Point) -> Point {
        Point {x: self.x + other.x, y: self.y + other.y}
    }
}

fn main() {
    let p: Point = Point {x: 1, y: 0};
    let pp = p + p;
}

由于拥有p导致编译器错误:

<anon>:21:18: 21:19 error: use of moved value: `p`
<anon>:21     let pp = p + p;
                           ^
<anon>:21:14: 21:15 note: `p` moved here because it has type `Point`, which is non-copyable
<anon>:21     let pp = p + p;
                       ^

此处解释了其原理.导致 RFC 被接受(部分原因是由于上述原因例子).但是,随后的 RFC 仍为操作员引入了按值类型签名.

虽然我了解这项决定的依据.由于我缺乏生锈的经验,我不确定让上述代码正常工作的正确"方式是(a)如果我不想复制,或者(b)如何使结构可复制?

解决方案

如果您不想复制,那么据我的新手了解,您需要在对Point的引用上实现Add. /p>

这将由RFC支持:

幸运的是,在表达能力方面没有任何损失,因为您始终可以在引用类型上实现特征.但是,对于确实需要引用的类型,由于您可能需要显式地借用&来借用操作数,因此在人体工程学上会有一些损失.好处是所有权语义变得更清晰:它们更像正常的函数参数.

实际上似乎可行:

use std::ops::{Add};

#[derive(Show)]
struct Point {
    x: i32,
    y: i32
}

impl<'a> Add for &'a Point {
    type Output = Point;

    fn add(self, other: &'a Point) -> Point { //'
        Point {x: self.x + other.x, y: self.y + other.y}
    }
}

fn main() {
    let p: Point = Point {x: 1, y: 0};
    let pp = &p + &p;
    println!("{:?}", pp);
}

(游戏围栏)

要改为复制Point,只需将#[derive(Show)]替换为#[derive(Show,Copy)].这种结构默认情况下是可复制的,但是更改.

Compiling the following Rust code that uses operator overloading

use std::ops::{Add};

#[derive(Show)]
struct Point {
    x: int,
    y: int
}

impl Add for Point {
    type Output = Point;

    fn add(self, other: Point) -> Point {
        Point {x: self.x + other.x, y: self.y + other.y}
    }
}

fn main() {
    let p: Point = Point {x: 1, y: 0};
    let pp = p + p;
}

Results in compiler errors due to ownership of p:

<anon>:21:18: 21:19 error: use of moved value: `p`
<anon>:21     let pp = p + p;
                           ^
<anon>:21:14: 21:15 note: `p` moved here because it has type `Point`, which is non-copyable
<anon>:21     let pp = p + p;
                       ^

The rationale behind it is explained here and led to an RFC that was not accepted (part of due to reasons of the above example). However, later the following RFC still introduced the by-value type signatures for operators.

While I understand the rationale behind the decision. Due to my lack of experience in rust, I'm not sure what the "proper" way would be to allow the above code to work (a) if I do not want to copy or (b) how to make the struct copyable?

解决方案

If you don't want to copy then, as far as my newbie understanding goes, you need to implement Add on references to Point.

This would be supported by the RFC:

Fortunately, there is no loss in expressiveness, since you can always implement the trait on reference types. However, for types that do need to be taken by reference, there is a slight loss in ergonomics since you may need to explicitly borrow the operands with &. The upside is that the ownership semantics become clearer: they more closely resemble normal function arguments.

And indeed it seems to work:

use std::ops::{Add};

#[derive(Show)]
struct Point {
    x: i32,
    y: i32
}

impl<'a> Add for &'a Point {
    type Output = Point;

    fn add(self, other: &'a Point) -> Point { //'
        Point {x: self.x + other.x, y: self.y + other.y}
    }
}

fn main() {
    let p: Point = Point {x: 1, y: 0};
    let pp = &p + &p;
    println!("{:?}", pp);
}

(playpen)

To make Point copyable instead, just replace #[derive(Show)] with #[derive(Show,Copy)]. Such structs used to be copyable by default, but it changed.

这篇关于操作员按值超载会导致使用已移动的值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆