-2

Is there a way to declare a generic trait that takes a function as the generic argument and uses it? To clarify (Non-functioning code):

pub trait Test<F, T> where F: Fn(i32) -> T {
    fn test(arg: i32) -> T {
        let func: F;
        func(arg)
    }
}
trent
  • 25,033
  • 7
  • 51
  • 90
Adam
  • 743
  • 1
  • 6
  • 11
  • 2
    why didn't you take f as param ? I don't understand your question – Stargateur Nov 27 '20 at 10:29
  • Does this answer your question? [How to pass anonymous functions as parameters in Rust?](https://stackoverflow.com/questions/25182565/how-to-pass-anonymous-functions-as-parameters-in-rust) – E_net4 Nov 27 '20 at 10:32
  • The actual function value needs to be passed somewhere. If it's not passed by `test`, it has to be made available in a concrete implementation of that `Test` trait. – E_net4 Nov 27 '20 at 10:34
  • 1
    It seems that you are asking to associate a specific function with trait while implementing it? AFAIK, it is possible for `const` functions only. Example: [Playground link](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=4cb22d6a12b6b93608e23800d1718870). Although, doing so doesn't seem very useful. Traits anyway do that only. All implementers provide different functionalities for the trait methods so what use would it be to associate a specific function? – Mihir Luthra Nov 27 '20 at 10:50
  • Thanks Mihir, that's exactly what I wanted to do. Is there no work around for non-const functions?. I would like to do something similar because I want a singular interface on types for several functions (one function per type). The number of functions is limited, but the number of types may grow with the project. It would be useful to identify them all with a single trait and to able to implement the appropriate method for each type with a simple: impl and template syntax. – Adam Nov 27 '20 at 11:11
  • 1
    If the reason to do this is code sanity, you could go with [proc-macros](https://doc.rust-lang.org/reference/procedural-macros.html). Then you can simply place a custom attribute over your trait impementation containing the path of the function to call. That's the best in my knowledge. Also, if you want to communicate with someone in comments, you should tag them like @Adam, otherwise they won't get a notification. – Mihir Luthra Nov 27 '20 at 12:23
  • 1
    Sorry, a mistake from my end. The function need NOT necessarily be returning a `const`. You can it without const too: [Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=61404465870f08307620610acb9552ac) – Mihir Luthra Nov 27 '20 at 12:34

2 Answers2

1

You can associate specific functions when implementing a trait (didn't knew about this until now):

fn func() -> String {
    String::from("hello")
}

trait MyTrait {
    const FUNC: fn() -> String;
}

struct MyType;

impl MyTrait for MyType {
    const FUNC: fn() -> String = func;
}

fn main() {
    println!("{}", (MyType::FUNC)()); // prints hello
}

Playground

Mihir Luthra
  • 6,059
  • 3
  • 14
  • 39
1

You can implement it somehow like this:

trait MyTrait<V: Sized + Fn() -> &'static str>: Sized {
    fn construct(fun: V) -> Self;
    fn get_fn(&self) -> &V;
    fn call_inner(&self) {
        println!("{}", (self.get_fn())());
    }
}

struct FuncitonContainer<V>
where
    V: Sized + Fn() -> &'static str,
{
    f: V,
}

impl<V> MyTrait<V> for FuncitonContainer<V>
where
    V: Sized + Fn() -> &'static str,
{
    fn construct(fun: V) -> Self {
        Self { f: fun }
    }
    fn get_fn(&self) -> &V {
        &self.f
    }
}

fn main() {
    fn get_hello() -> &'static str {
        "Hello"
    }
    FuncitonContainer::construct(get_hello).call_inner();
    FuncitonContainer::construct(|| "World").call_inner();
}

It preserves function info and allows to use closures too. However, using it can be little more complex than Mihir's answer.

You can also look how Rust iterators are implemented: Rust iterators implementation

Mihir Luthra
  • 6,059
  • 3
  • 14
  • 39
  • It is a good approach to solve such problems. Although, till what I understood by comments under question, it seemed OP was specifically asking for associating funcs when implementing traits for some reason. But this design surely is more flexible. – Mihir Luthra Nov 27 '20 at 14:35