Невозможно перегрузить оператор add для структуры, содержащей Cow, потому что я не могу вернуть значение, ссылающееся на локальные данные - PullRequest
0 голосов
/ 01 апреля 2020

Я реализую основные операции c для матриц в поле c F. При этом я хочу перегрузить оператор добавления для типа матрицы. Тип матрицы содержит Cow владеющий или заимствующий F. Я хочу, чтобы полученная сумма матрицы заняла F добавленной матрицы независимо от того, владеет ли она или занимает F.

. Компилятор жалуется, что я возвращаю ссылку, созданную внутри функции, но я не понимаю почему. Мне кажется, я ссылаюсь на входной аргумент функции, а не на данные, созданные локально. Вот мой минимальный пример:

use std::{
    borrow::{Borrow, Cow},
    ops::Add,
};

pub trait Field {
    type FElt: Copy + Eq;

    fn zero(&self) -> Self::FElt;
    fn add(&self, a: Self::FElt, b: Self::FElt) -> Self::FElt;
}

pub struct Mat<'a, F: Clone + Eq + Field> {
    field: Cow<'a, F>,
    rows: usize,
    cols: usize,
    data: Vec<F::FElt>,
}

impl<'a, F: Clone + Eq + Field> Mat<'a, F> {
    pub fn zero(field: &'a F, rows: usize, cols: usize) -> Self {
        if rows == 0 || cols == 0 {
            panic!("Empty matrix");
        }

        Self {
            field: Cow::Borrowed(field),
            rows,
            cols,
            data: vec![field.zero(); rows * cols],
        }
    }
}

impl<'a, F: Clone + Eq + Field> Add for Mat<'a, F> {
    type Output = Self;

    fn add(self, other: Self) -> Self::Output {
        if self.field != other.field {
            panic!("Cannot add matrices: fields do not match");
        }
        if self.rows != other.rows || self.cols != other.cols {
            panic!("Cannot add matrices: dimensions do not match");
        }

        let f: &F = self.field.borrow();
        let mut sum = Mat::zero(f, self.rows, self.cols);
        for i in 0..self.rows * self.cols {
            sum.data[i] = f.add(self.data[i], other.data[i]);
        }
        sum
    }
}

fn main() {}

Вот ошибка, которую я получаю:

error[E0515]: cannot return value referencing local data `self.field`
  --> src/main.rs:51:9
   |
46 |         let f: &F = self.field.borrow();
   |                     ---------- `self.field` is borrowed here
...
51 |         sum
   |         ^^^ returns a value referencing data owned by the current function

1 Ответ

1 голос
/ 01 апреля 2020

Мне кажется, я ссылаюсь на входной аргумент функции, а не на данные, созданные локально.

self, возможно, не был создан локально , но он перемещен в метод add (который занимает self), поэтому он все равно будет уничтожен, когда функция вернется. Если бы выводу было разрешено ссылаться на него, ссылка стала бы зависшей, как только функция вернулась.

Если вы хотите, чтобы вывод заимствовался из ввода, вы должны принять вход в качестве ссылки, что означает реализацию Add для &'b Mat<'a, F> вместо Mat<'a, F>. См. Как реализовать черту Add для ссылки на структуру? Обратите внимание, что тип Output должен быть Mat<'b, F> вместо Mat<'a, F>.

Существует другое, более простое решение. для проблемы, как поставлено. Заимствование не работает, потому что Cow был добавлен в функцию. Почему бы просто не переместить его обратно? Простой способ сделать это - изменить self и вернуть его вместо создания sum внутри функции.

    fn add(mut self, other: Self) -> Self::Output {
        /* ... */

        for i in 0..self.rows * self.cols {
            self.data[i] = self.field.add(self.data[i], other.data[i]);
        }
        self
    }

Вы не только избегаете потенциально дорогого клона field, но и также используйте буфер data таким образом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...