简体   繁体   中英

How to name the type of an associated function in Rust?

I'm trying to write code which is generic over an operation, but also has convenience functions for commonly used ones, like addition, which I want to define for all types T: Add .

This works fine if I define standalone functions since I can use impl Trait in the return value to hide the opaque type.

However, if I want to define this function inside a trait, I am forced to name the type of <T as Add>::add . How can I do this?

use std::ops::Add;

struct Operation<T, F>
where
    F: Fn(T, T) -> T,
{
    arg: T,
    f: F,
}

fn addition<T>(arg: T) -> Operation<T, impl Fn(T, T) -> T>
where
    T: Add<Output = T>,
{
    Operation { arg, f: T::add }
}

trait Addable<T>
where
    T: Add<Output = T>,
{
    fn addition(self) -> Operation<T, impl Fn(T, T) -> T>;
    //fn addition(self) -> Operation<T, ???>;
}

Error:

error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
  --> src/main.rs:22:39
   |
22 |     fn addition(self) -> Operation<T, impl Fn(T, T) -> T>;
   |                                       ^^^^^^^^^^^^^^^^^^

The reason impl Trait isn't allowed in the return position of trait methods is because there can be multiple implementations of the method, whereas impl Trait is only valid if there's a single implementation of the function or method.

One option would be to use a boxed trait object closure:

trait Addable<T>
where
    T: Add<Output = T>,
{
    fn addition(self) -> Operation<T, Box<dyn Fn(T, T) -> T>>;
}

However, since it seems unlikely that the closure would ever need to capture variables from its environment you can use a plain function pointer instead. This saves you an unnecessary heap allocation. Here's a simple i32 example using a plain function pointer in the trait method return type:

trait Addable<T>
where
    T: Add<Output = T>,
{
    fn addition(self) -> Operation<T, fn(T, T) -> T>;
}

struct SomeType {
    arg: i32,
}

impl Addable<i32> for SomeType {
    fn addition(self) -> Operation<i32, fn(i32, i32) -> i32> {
        Operation {
            arg: self.arg,
            f: i32::add,
        }
    }
}

Here's a generic example using plain function pointer in the trait method return type:

trait Addable<T>
where
    T: Add<Output = T>,
{
    fn addition(self) -> Operation<T, fn(T, T) -> T>;
}

struct SomeType<T> {
    arg: T,
}

impl<T> Addable<T> for SomeType<T>
    where T: Add + Add<Output = T>
{
    fn addition(self) -> Operation<T, fn(T, T) -> T> {
        Operation {
            arg: self.arg,
            f: T::add,
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM