按值重载运算符会导致使用移动的值
Operator overloading by value results in use of moved value
编译以下使用运算符重载的 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;
^
解释其背后的基本原理here and led to an RFC that was not accepted (part of due to reasons of the above example). However, later the following RFC仍然介绍了运算符的按值类型签名。
虽然我理解该决定背后的理由。由于我缺乏 rust 经验,我不确定 "proper" 允许上述代码工作的方式是什么(a)如果我不想复制或(b)如何制作结构可复制?
如果您不想复制,就我的新手理解而言,您需要在对 Point
.
的引用上实现 Add
这将得到 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.
而且确实有效:
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)
要使 Point
可复制,只需将 #[derive(Show)]
替换为 #[derive(Show,Copy)]
。这种结构过去默认是可复制的,但它 changed.
如果您的结构无法复制(例如,它具有 Drop
实现,无论是本身还是其中一个字段),那么创建多个实现可能是有意义的:value+value、value+参考、参考+值和参考+参考。前三个可以重用其中一个操作数的存储,最后一个可以克隆其中一个操作数,然后只委托给已经存在的实现。这样,您的图书馆的用户可以轻松决定他们是否要重用现有值进行优化。
事实上,这就是例如BigInt
or Complex
类型已处理。
但是,您的 Point
可以制作 Copy
,因为复制它很便宜。
编译以下使用运算符重载的 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;
^
解释其背后的基本原理here and led to an RFC that was not accepted (part of due to reasons of the above example). However, later the following RFC仍然介绍了运算符的按值类型签名。
虽然我理解该决定背后的理由。由于我缺乏 rust 经验,我不确定 "proper" 允许上述代码工作的方式是什么(a)如果我不想复制或(b)如何制作结构可复制?
如果您不想复制,就我的新手理解而言,您需要在对 Point
.
Add
这将得到 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.
而且确实有效:
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)
要使 Point
可复制,只需将 #[derive(Show)]
替换为 #[derive(Show,Copy)]
。这种结构过去默认是可复制的,但它 changed.
如果您的结构无法复制(例如,它具有 Drop
实现,无论是本身还是其中一个字段),那么创建多个实现可能是有意义的:value+value、value+参考、参考+值和参考+参考。前三个可以重用其中一个操作数的存储,最后一个可以克隆其中一个操作数,然后只委托给已经存在的实现。这样,您的图书馆的用户可以轻松决定他们是否要重用现有值进行优化。
事实上,这就是例如BigInt
or Complex
类型已处理。
但是,您的 Point
可以制作 Copy
,因为复制它很便宜。