Как передать функции для признаков, реализованных с временами жизни? - PullRequest
0 голосов
/ 03 ноября 2018

Ржавчина новичка здесь. У меня есть этот «двоичный калькулятор», который использует несколько типов ..

pub enum Bit { Off, On };
pub struct Binary([Bit; 64]);

Игнорируя все остальное, что для них реализовано, я перегрузил операторы для Binary вот так ...

impl Add for Binary {
    type Output = Binary;

    /// Basic implementation of full addition circuit
    fn add(self, other: Binary) -> Binary {
        ...
    }
}

... Div, Sub, and Mul

... где каждый оператор потребляет переданные им Binary s. Затем я смог определить набор общедоступных функций, которые заботились о преобразовании, вызове и печати всего, что я хотел ...

pub fn add(x: i64, y: i64) -> Calc {
    execute(Binary::add, x, y)
}

pub fn subtract(x: i64, y: i64) -> Calc {
    execute(Binary::sub, x, y)
}

...

fn execute(f: fn(Binary, Binary) -> Binary, x: i64, y: i64) -> Calc {
    let bx = Binary::from_int(x);
    println!("{:?}\n{}\n", bx, x);

    let by = Binary::from_int(y);
    println!("{:?}\n{}\n", by, y);

    let result = f(bx, by);
    println!("{:?}", result);

    result.to_int()
}

1012 * проблема * Это сработало, но операции потребляли Binary с, чего я на самом деле не хотел. Поэтому вместо этого я реализовал черты, используя ссылки ... impl<'a, 'b> Add<&'b Binary> for &'a Binary { type Output = Binary; /// Basic implementation of full addition circuit fn add(self, other: &'b Binary) -> Binary { ... } } Теперь, однако, я не могу понять, как передать эти функции в execute, как я делал раньше. Например, execute(Binary::div, x, y) выдает следующую ошибку. error[E0277]: cannot divide `types::binary::Binary` by `_` --> src/lib.rs:20:13 | 20 | execute(Binary::div, x, y) | ^^^^^^^^^^^ no implementation for `types::binary::Binary / _` | = help: the trait `std::ops::Div<_>` is not implemented for `types::binary::Binary` Как я могу передать эту конкретную реализацию со временем жизни? Я предполагаю, что мне нужно обновить подпись для execute тоже, как ... fn execute<'a, 'b>(f: fn(&'a Binary, &'b Binary) -> Binary, ... Но я тоже вижу ... error[E0308]: mismatched types --> src/lib.rs:20:13 | 20 | execute(Binary::div, x, y) | ^^^^^^^^^^^ expected reference, found struct `types::binary::Binary` | = note: expected type `fn(&types::binary::Binary, &types::binary::Binary) -> types::binary::Binary` found type `fn(types::binary::Binary, _) -> <types::binary::Binary as std::ops::Div<_>>::Output {<types::binary::Binary as std::ops::Div<_>>::div}` Будучи полным новичком, я мог следить за всеми сообщениями об ошибках, которые приводили меня к «рабочей» точке (где операции потребляли значения), но я думаю, что теперь я немного вне своей лиги.

1 Ответ

0 голосов
/ 03 ноября 2018

Я сделал примерную реализацию для добавления (я сделал некоторые предположения относительно типа возврата execute и другие, вам придется адаптировать это, если мои предположения неверны):

use std::ops::Add;

#[derive(Debug)]
pub enum Bit { Off, On }
#[derive(Debug)]
pub struct Binary([Bit; 32]);

impl Binary {
    fn to_int(&self) -> i64 {unimplemented!()}
    fn from_int(n: i64) -> Self {unimplemented!()}
}

impl<'a, 'b> Add<&'b Binary> for &'a Binary {
    type Output = Binary;
    fn add(self, other: &'b Binary) -> Binary {
        unimplemented!()
    }
}

pub fn add(x: i64, y: i64) -> i64 {
   execute(|a, b| a+b, x, y)
}

fn execute(f: fn(&Binary, &Binary) -> Binary, x: i64, y: i64) -> i64 {
    let bx = Binary::from_int(x);
    println!("{:?}\n{}\n", bx, x);

    let by = Binary::from_int(y);
    println!("{:?}\n{}\n", by, y);

    let result = f(&bx, &by);
    println!("{:?}", result);

    result.to_int()
}

Обратите внимание, что в пределах execute вам нужно будет позвонить f(&bx, &by) (т.е. одолжить их вместо того, чтобы потреблять).

Однако: я удивился, почему вы выбрали fn(&Binary, &Binary) -> Binary в качестве типа аргумента вместо того, чтобы сделать execute универсальным для F, ограничив F быть вызываемым:

fn execute<F>(f: F, x: i64, y: i64) -> i64
    where
        F: Fn(&Binary, &Binary) -> Binary,
{
    let bx = Binary::from_int(x);
    println!("{:?}\n{}\n", bx, x);

    let by = Binary::from_int(y);
    println!("{:?}\n{}\n", by, y);

    let result = f(&bx, &by);
    println!("{:?}", result);

    result.to_int()
}

Таким образом, вы немного более гибки (например, вы можете передавать замыкания, захватив переменные в их области видимости).

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