如何为使用生命周期实现的特征传递函数?

时间:2018-11-02 21:26:53

标签: rust

这里是生锈的初学者。我有一个使用两种类型的“二进制计算器”。

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。然后,我可以定义一组公共函数,这些函数负责转换,调用和打印我想要的所有内容...

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()
}

问题

这有效,但是操作消耗了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}`

作为一个完整的初学者,我能够跟踪所有使我到达“工作”点(操作消耗了值)的错误消息,但是现在,我觉得我有点不合时宜了。 / p>

1 个答案:

答案 0 :(得分:1)

我为加法做了一个示例性的实现(我对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()
}

这样,您会更加灵活(例如,可以传递闭包来捕获变量范围内的变量)。