当前位置: 动力学知识库 > 问答 > 编程问答 >

"Ambiguous associated type" when returning a generic lambda

问题描述:

I have this code (contrived and purely experimental)

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

}

It returns a function/lambda that takes two operands and returns a result (in this case the addition, subtraction, divide and multiply operators)

Which can be called like so:

let add: Option<Box<Fn(i32, i32) -> i32>> = math_op("+");

println!("Add {}", add.unwrap()(10, 2));

I would really like to make a generic version of this, so far I have...

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

}

But when I build I get these errors:

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`

I understand this is because the compiler cannot determine what type T::Output is from the various traits I have implemented. Is there another way of writing this to get it to work?

网友答案:

You need the output types of Add, Sub, Mul and Div to be the same. You can enforce this by adding another type parameter and constraining each trait's Output to be this type parameter.

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
}
分享给朋友:
您可能感兴趣的文章:
随机阅读: