2015-01-09 1 views
7

Compiling следующего 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; 
} 

приводит к ошибкам компилятора из-за владения р:

<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 и привел к RFC, который не был принят (часть из-за причин приведенного выше примера). Однако позже следующие RFC по-прежнему вводили сигнатуры типа байтов для операторов.

Хотя я понимаю обоснование решения. Из-за моего отсутствия опыта в ржавчине, я не уверен, что «правильный» способ мог бы позволить вышеуказанному коду работать (а), если я не хочу копировать, или (б) как сделать структуру с возможностью копирования?

ответ

4

Если вы не хотите копировать, то, насколько я понимаю мой новичок, вам необходимо реализовать Add по ссылкам на Point.

Это будет поддерживаться в 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); 
} 

(playpen)

Чтобы Point копируемыми вместо просто заменить #[derive(Show)] с #[derive(Show,Copy)]. Такие структуры использовались для копирования по умолчанию, но это changed.

+1

Проблема в том, что 'let pp = & p + & p + & p' не работает. – SirVer

+0

@SirVer да, вам нужно написать что-то вроде 'let pp = & (& p + & p) + & p'. Я предполагаю, что практическая задача - создать несколько реализаций, как предлагает Владимир Матвеев (или просто вывести «Копировать» и сделать с ним). –

4

Если ваша структура не может быть скопирована (например, она имеет реализацию Drop, либо сама, либо для одного из ее полей), тогда может иметь смысл создать несколько реализаций: значение + значение, значение + ссылка, ссылка + значение и ссылку + ссылку. Первые три могут повторно использовать память одного из операндов, а последний может клонировать один из операндов, а затем просто делегировать на уже существующие реализации. Таким образом, пользователь вашей библиотеки может легко решить, хотят ли они повторно использовать существующие значения для оптимизации или нет.

Фактически, именно так. BigInt или Complex.

Ваш Point, однако, можно просто сделать Copy, так как это дешево его скопировать.

+0

Владимир, спасибо за ваш ответ. Что делать, если мой тип прост, но дорого скопирован, скажем, тип «Matrix1000x1000»?Является ли компилятор достаточно умным, чтобы избежать копирования в цепочных операциях или мне нужно написать тривиально вперед к 4 реализациям, которые вы упомянули? – SirVer

+1

Я не уверен, что понимаю ваш вопрос. Если ваш тип дорогой для копирования, не делайте его «Копировать» и реализуйте черты функционирования для четырех вариантов (self + self, & self + self, self + & self, & self + & self). Если ваш тип такой большой, вам нужно будет поместить данные в кучу в любом случае, поэтому семантика переноса будет гарантировать, что будет скопирована только сама структура. –

Смежные вопросы