"模糊相关类型"当返回通用lambda时

时间:2015-10-18 00:11:28

标签: generics lambda rust

我有这个代码(设计和纯实验)

fn math_op(op: &str) -> Option<Box<Fn(i32, i32) -> i32>> {
    let ret: Option<Box<Fn(i32, i32) -> i32>> = match op {
        "+" => Some(Box::new(|a: i32, b: i32| -> i32 { a + b } )),
        "-" => Some(Box::new(|a: i32, b: i32| -> i32 { a - b } )),
        "*" => Some(Box::new(|a: i32, b: i32| -> i32 { a * b } )),
        "/" => Some(Box::new(|a: i32, b: i32| -> i32 { a / b } )),
        _ => None,
    };

    ret
}

它返回一个函数/ lambda,它接受两个操作数并返回一个结果(在这种情况下是加法,减法,除法和乘法运算符)

可以这样称呼:

let add: Option<Box<Fn(i32, i32) -> i32>> = math_op("+");
println!("Add {}", add.unwrap()(10, 2));

我真的想制作一个通用版本,到目前为止我已......

fn math_op_gen<T>(op: &str) -> Option<Box<Fn(T, T) -> T::Output>> 
    where T: std::ops::Add + std::ops::Sub + std::ops::Mul + std::ops::Div {
        let ret: Option<Box<Fn(T, T) -> T::Output>> = match op {
            "+" => Some(Box::new(|a, b| { a + b } )),
            "-" => Some(Box::new(|a, b| { a - b } )),
            "*" => Some(Box::new(|a, b| { a * b } )),
            "/" => Some(Box::new(|a, b| { a / b } )),
            _ => None,
        };

        ret
}

但是当我构建时,我得到了这些错误:

error: ambiguous associated type `Output` in bounds of `T` [E0221]
note: associated type `T` could derive from `core::ops::Div`
note: associated type `T` could derive from `core::ops::Mul`
note: associated type `T` could derive from `core::ops::Sub`
note: associated type `T` could derive from `core::ops::Add`

我理解这是因为编译器无法确定T :: Output的类型来自我实现的各种特性。有没有其他方式来写这个来让它工作?

1 个答案:

答案 0 :(得分:4)

您需要AddSubMulDiv的输出类型相同。您可以通过添加其他类型参数并将每个特征的Output约束为此类型参数来强制执行此操作。

fn math_op_gen<T, R>(op: &str) -> Option<Box<Fn(T, T) -> R>> 
    where T: std::ops::Add<Output=R> +
             std::ops::Sub<Output=R> +
             std::ops::Mul<Output=R> +
             std::ops::Div<Output=R> {
        let ret: Option<Box<Fn(T, T) -> R>> = match op {
            "+" => Some(Box::new(|a, b| { a + b } )),
            "-" => Some(Box::new(|a, b| { a - b } )),
            "*" => Some(Box::new(|a, b| { a * b } )),
            "/" => Some(Box::new(|a, b| { a / b } )),
            _ => None,
        };

        ret
}