Where clause in Rust


#1

Hi, what’s the difference between the following code? why the first one is wrong, but the second is right?

The Scala can support the first one, which means we can pass the function directly.

fn myfunc(data: i32, f: Fn(i32) -> i32){   
    let ans = f(data);
    println!("{}", ans);
}

fn myfunc2<F>(data: i32, f: F) where F: Fn(i32) -> i32 {
    let ans = f(data);
    println!("{}", ans);
    
}

#2

myfunc2 is generic over all types F which implement Fn(i32) -> i32. That is, you can pass a value of any compatible type for the second parameter.

myfunc attempts to define a single, non-generic function where the second parameter must be precisely of type Fn(i32) -> i32. However, that is an “object type” (a trait used in type position), and you can’t have values of object type. Thus, myfunc cannot possibly be called, and the definition is invalid.


#3

@DanielKeep is right. I want to add that you don’t need a where clause to create a generic function. Here is an example

trait Thing {
    fn do_something(&self);
}


fn staic_dispatch1<T: Thing>(t: &T) {
    t.do_something()
}

fn static_dispatch2<T>(t: &T) where T: Thing {
    t.do_something()
}

fn dynamic_dispatch(t: &Thing) { 
    t.do_something()
}

fn compile_time_error(t: Thing) { }

The relevant docs are here


#4

@DanielKeep @matklad Thanks for your answer!

I understand all this now.
I can either use a static dispatch way just as myfunc2, or I can use a dynamic dispatch way as the following way

fn myfunc(data: i32, f: &Fn(i32) -> i32){   
    let ans = f(data);
    println!("{}", ans);
}