This question already has answers here:
How do you pass a Rust function as a parameter?
(2 answers)
Closed 4 years ago.
fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 { // definition
f(arg) + f(arg)
}
do_twice(|x| x + 1, 5) // call
This function accepts both, closures and function pointers. It takes a function pointer as parameter type.
When should I prefer this over using a trait object, like &dyn Fn(i32) -> i32 or Box<dyn Fn(i32)-> i32> instead of fn
fn do_twice(f: &dyn Fn(i32) -> i32, arg: i32) -> i32 { // definition
f(arg) + f(arg)
}
do_twice(&|x| x + 1, 5) // call
or
fn do_twice(f: Box<dyn Fn(i32) -> i32>, arg: i32) -> i32 { // definition
f(arg) + f(arg)
}
When should I prefer this over using a trait object
Trait objects are not the only other option. As #DarthKotik pointed out, accepting a fn pointer will not permit closures that capture their environment, but you can just use a normal type parameter, bounded by Fn to accept both functions and closures, without needing to box anything:
fn do_twice<F>(f: F, arg: i32) -> i32
where
F: Fn(i32) -> i32
{
f(arg) + f(arg)
}
Or, equivalently, but avoiding an extra type variable:
fn do_twice(f: impl Fn(i32) -> i32, arg: i32) -> i32 {
f(arg) + f(arg)
}
fn type is a bare function pointer (https://doc.rust-lang.org/std/primitive.fn.html).
It won't work with the closure that captures environment and it cannot be implemented manually for your fancy type (like impl Fn for MySuperType)
So the only reason why your examples working is the fact that it's oversimplified!
if you make it just a bit more complicated, it will fail https://gist.github.com/rust-play/2167e73325daa1e2a179505209405917
Related
I have a function that takes 3 arguments namely a, b and a function that takes them and return the value that function produed.
fn from_func<T>(a: i32, b: i32, func: Fn) -> i32 {
func(a, b)
}
but when im calling it :
fn main() {
let my_func = |a: i32, b: i32| a + b;
println!("{:?}", from_func(15, 20, my_func));
}
I'm getting
error[E0191]: the value of the associated type `Output` (from trait `FnOnce`) must be specified
--> src\main.rs:5:34
|
5 | fn from_func<T>(a:i32,b:i32,func:Fn)->i32{
| ^^ help: specify the associated type: `Fn<Output = Type>`
I tried using where keyword and it worked
fn from_func<T>(a: i32, b: i32, func: T) -> i32
where
T: Fn(i32, i32) -> i32
{
func(a,b)
}
but is there any other way of doing this?
but is there any other way of doing this?
You must constrain the type variable to provide the arguments and return type of the function. You can do that with a where clause, which is probably best because it's on another line so makes the signature less cluttered.
But you could do this:
fn from_func<F: Fn(i32, i32) -> i32>(a: i32, b: i32, func: F) -> i32 {
func(a, b)
}
Or, avoid a named type variable by using an impl trait, like this:
fn from_func(a: i32, b: i32, func: impl Fn(i32, i32) -> i32) -> i32 {
func(a, b)
}
This question already has answers here:
Returning a closure from a method of a generic struct
(2 answers)
Closed 8 months ago.
I have a struct
struct A<F: Fn(i32)->i32>
How to define function which return it like
fn some_function() -> A<Fn(i32)->i32>
?
I think you need to use the fn type instead of the Fn trait:
struct A(fn(i32) -> i32);
fn some_function() -> A {
let square = |x| x * x;
A(square)
}
fn main() {
let f = some_function();
println!("{}", f.0(7));
}
49
You can of course also use the Fn trait, but then you need to use the impl keyword:
struct A<T: Fn(i32) -> i32>(T);
fn some_function() -> A<impl Fn(i32) -> i32> {
let square = |x| x * x;
A(square)
}
fn main() {
let f = some_function();
println!("{}", f.0(7));
}
49
impl here means "this is a type that I don't want to write here completely, but believe me, it implements Fn(i32) -> i32".
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)
}
}
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
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
I attempt to implement a currying function similar to Functional Programming Jargon in Rust:
fn add_origin(x: i32) -> impl Fn(i32) -> i32 {
return move |y| {
x + y
};
}
fn main() {
let add5 = add_origin(5);
println!("Call closure: {}", add5(6));
}
This works, but if I add one level deeper:
fn add(x: i32) -> impl Fn(i32) -> impl Fn(i32) -> i32 {
return move |y: i32| {
return move |z: i32| {
x + y + z
}
};
}
fn main() {
let add5 = add(5);
let add5_10 = add5(10);
println!("Call closure: {}", add5_10(6));
}
Compiler does not accept and tells me:
error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
--> src/main.rs:7:35
|
7 | fn add(x: i32) -> impl Fn(i32) -> impl Fn(i32) -> i32 {
| ^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
Why is this not allowed? Is there a better alternative in Rust?
impl Trait syntax can only be used in argument position or return position of a function signature. Both of these are fine:
fn takes_fn(fn_arg: impl Fn(i32) -> i32) {}
fn returns_fn() -> impl Fn(i32) -> i32 {
|x| x
}
However neither of these work:
fn takes_fn(fn_arg: impl Fn(i32) -> impl Fn(i32) -> i32) {}
fn returns_fn() -> impl Fn(i32) -> impl Fn(i32) -> i32 {
|x| x
}
Because the second nested impl Trait is no longer in argument or return position but is now part of the argument or return type's signature, which is not somewhere where it is allowed. Basically, multiple nested impl Traits will never work regardless of where you place them and you'll always get the same compile error.
The good news is this doesn't stop you from accomplishing what you want to accomplish because impl Trait is just syntax sugar and its use is optional. In your particular example we can use a boxed trait object to return your curried function.
fn add(x: i32) -> impl Fn(i32) -> Box<dyn Fn(i32) -> i32> {
move |y: i32| {
Box::new(move |z: i32| {
x + y + z
})
}
}
fn main() {
let add5 = add(5);
let add5_10 = add5(10);
println!("Call closure: {}", add5_10(6)); // prints "Call closure: 21"
}
playground
See also:
What does `impl` mean when used as the argument type or return type of a function?
What makes `impl Trait` as an argument "universal" and as a return value "existential"?
Given the following rust program:
fn call_twice<A>(val: A, f: fn(A) -> A) -> A {
f(f(val))
}
fn main() {
fn double(x: int) -> int {x + x};
println!("Res is {}", call_twice(10i, double));
// println!("Res is {}", call_twice(10i, (x: int) -> int {x + x}));
// ^ this line will fail
}
Why can I pass double as the function, but not inlined? What is a good way to achieve the same behaviour without defining the function somewhere?
2016-04-01 Update:
As of Rust 1.0, the code should look like this:
fn call_twice<A, F>(val: A, mut f: F) -> A
where F: FnMut(A) -> A {
let tmp = f(val);
f(tmp)
}
fn main() {
fn double(x: i32) -> i32 {x + x};
println!("Res is {}", call_twice(10, double));
println!("Res is {}", call_twice(10, |x| x + x));
}
The change to the closure parameter is because closure are now unboxed.
Original:
Insofar as I know, you can't define functions inline like that.
What you want is a closure. The following works:
fn call_twice<A>(val: A, f: |A| -> A) -> A {
let tmp = f(val);
f(tmp)
}
fn main() {
fn double(x: int) -> int {x + x};
println!("Res is {}", call_twice(10i, double));
println!("Res is {}", call_twice(10i, |x| x + x));
}
There are a few things to note:
Functions coerce to closures, but the opposite isn't true.
You need to store the result of f(val) in a temporary due to borrowing rules. Short version: you need unique access to a closure to call it, and the borrow checker isn't quite clever enough to realise the two calls are independent in their original positions.
Closures are in the process of being replaced by unboxed closures, so this will change in the future, but we're not quite there yet.