Constraining closure type parameters

I'm trying to write some code that deals generically with the argument and output types of closures. Everything I try that uses Fn(...)->... syntax results in an error of "unconstrained type parameter", and if I try to use Fn<...>, the compiler says to use the other form. What do I need to do to make this sort of construction compile?

Edit: The bounds need to be on the impl block because I am encountering this when trying to implement a trait; I'm not allowed to arbitrarily restrict associated functions that are supposed to be present.

struct WrappedFn<F>(F);

impl <I:From<&'static str>,O,F:Fn(I)->O> WrappedFn<F> {
    fn call(&self, s:&'static str)->O { (self.0)(s.into()) }
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error[E0207]: the type parameter `I` is not constrained by the impl trait, self type, or predicates
 --> src/lib.rs:3:7
  |
3 | impl <I:From<&'static str>,O,F:Fn(I)->O> WrappedFn<F> {
  |       ^ unconstrained type parameter

error[E0207]: the type parameter `O` is not constrained by the impl trait, self type, or predicates
 --> src/lib.rs:3:28
  |
3 | impl <I:From<&'static str>,O,F:Fn(I)->O> WrappedFn<F> {
  |                            ^ unconstrained type parameter

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0207`.
error: could not compile `playground`.

To learn more, run the command again with --verbose.

You can put the generic parameters on the function instead.

struct WrappedFn<F>(F);

impl<F> WrappedFn<F> {
    fn call<I, O>(&self, s: &'static str) -> O
    where
        F: Fn(I) -> O,
        &'static str: Into<I>,
    {
        (self.0)(s.into())
    }
}
1 Like

That solution doesn't work when it's an impl Trait for ... block, unfortunately, which is my actual usecase-- I removed that detail when minimizing my example.

It looks like I can get something working by including a PhantomData function pointer that uses the parameters:

use std::marker::PhantomData as PhD;

trait MyCall { fn call(&self, _:&'static str)->String; }

struct WrappedFn<I,O,F>(F, PhD<fn(I)->O>);

impl <I,O,F> WrappedFn<I,O,F> where WrappedFn<I,O,F>: MyCall {
    pub fn new(f:F)->Self { WrappedFn(f,PhD) }
}

impl <I:From<&'static str>,O:Into<String>,F:Fn(I)->O>
MyCall for WrappedFn<I,O,F> {
    fn call(&self, s:&'static str)->String { (self.0)(s.into()).into() }
}

(Playground)

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.