Can I pass a function as a parameter? If not, what is a good alternative?
I tried some different syntaxes but I have not found the right one. I know I can do this:
fn example() {
let fun: fn(value: i32) -> i32;
fun = fun_test;
fun(5i32);
}
fn fun_test(value: i32) -> i32 {
println!("{}", value);
value
}
but that's not passing the function as a parameter to another function:
fn fun_test(value: i32, (some_function_prototype)) -> i32 {
println!("{}", value);
value
}
Sure you can:
fn fun_test(value: i32, f: &dyn Fn(i32) -> i32) -> i32 {
println!("{}", f(value));
value
}
fn times2(value: i32) -> i32 {
2 * value
}
fn main() {
fun_test(5, ×2);
}
As this is Rust, you have to take into account the ownership and lifetime of the closure.
TL;DR; Basically there are 3 types of closures (callable objects):
Fn: It cannot modify the objects it captures.
FnMut: It can modify the objects it captures.
FnOnce: The most restricted. Can only be called once because when it is called it consumes itself and its captures.
See When does a closure implement Fn, FnMut and FnOnce? for more details
If you are using a simple pointer-to-function like closure, then the capture set is empty and you have the Fn flavor.
If you want to do more fancy stuff, then you will have to use lambda functions.
In Rust there are proper pointers to functions, that work just like those in C. Their type is for example fn(i32) -> i32. The Fn(i32) -> i32, FnMut(i32) -> i32 and FnOnce(i32) -> i32 are actually traits. A pointer to a function always implements all three of these, but Rust also has closures, that may or may not be converted to pointers (depending on whether the capture set is empty) to functions but they do implement some of these traits.
So for example, the example from above can be expanded:
fn fun_test_impl(value: i32, f: impl Fn(i32) -> i32) -> i32 {
println!("{}", f(value));
value
}
fn fun_test_dyn(value: i32, f: &dyn Fn(i32) -> i32) -> i32 {
println!("{}", f(value));
value
}
fn fun_test_ptr(value: i32, f: fn(i32) -> i32) -> i32 {
println!("{}", f(value));
value
}
fn times2(value: i32) -> i32 {
2 * value
}
fn main() {
let y = 2;
//static dispatch
fun_test_impl(5, times2);
fun_test_impl(5, |x| 2*x);
fun_test_impl(5, |x| y*x);
//dynamic dispatch
fun_test_dyn(5, ×2);
fun_test_dyn(5, &|x| 2*x);
fun_test_dyn(5, &|x| y*x);
//C-like pointer to function
fun_test_ptr(5, times2);
fun_test_ptr(5, |x| 2*x); //ok: empty capture set
fun_test_ptr(5, |x| y*x); //error: expected fn pointer, found closure
}
Fn, FnMut and FnOnce, outlined in the other answer, are closure types. The types of functions that close over their scope.
Apart from passing closures Rust also supports passing simple (non-closure) functions, like this:
fn times2(value: i32) -> i32 {
2 * value
}
fn fun_test(value: i32, f: fn(i32) -> i32) -> i32 {
println!("{}", f (value));
value
}
fn main() {
fun_test (2, times2);
}
fn(i32) -> i32 here is a function pointer type.
If you don't need a full-fledged closure than working with function types is often simpler as it doesn't have to deal with those closure lifetime nicities.
Related
Is there a shorter way of writing these function signatures?
fn hof_five(a: i32, func: impl Fn(i32) -> i32) -> impl Fn(i32) -> i32 {
move |v| func(a + v)
}
fn hof_six(a: i32, func: Box<dyn Fn(i32) -> i32>) -> Box<dyn Fn(i32) -> i32> {
Box::new(move |v| func(a + v))
}
Something like using F: impl Fn(i32) -> i32 or F: Box<dyn Fn(i32) -> i32>
So that the signature becomes something like:
fn hof_five<F>(a: i32, func: F) -> F {
move |v| func(a + v)
}
The two examples you gave are quite different.
fn hof_five(a: i32, func: impl Fn(i32) -> i32) -> impl Fn(i32) -> i32 {
move |v| func(a + v)
}
This function accepts a closure of a type implementing Fn(i32) -> i32, and returns a closure of a type implementing this trait, but the argument and return types are different types. The argument type is inferred by the compiler based on the closure you pass in, and the return type is inferred based on the closure you return. Each closure has its own individual type.
Since argument type and return type are different types, there is no way to refer to them by the same name. The only thing you could do is define a trait that requires Fn(i32) -> i32 as a prerequisite:
trait MyFn: Fn(i32) -> i32 {}
impl<T> MyFn for T
where
T: Fn(i32) -> i32,
{}
With this trait definition, you can rewrite hof_five as
fn hof_five(a: i32, func: impl MyFn) -> impl MyFn {
move |v| func(a + v)
}
The blanket implementation of MyFn makes sure that all closures implementing Fn(i32) -> i32 automatically also implement MyFn.
fn hof_six(a: i32, func: Box<dyn Fn(i32) -> i32>) -> Box<dyn Fn(i32) -> i32> {
Box::new(move |v| func(a + v))
}
This function accepts a pointer pointing to a closure implementing Fn(i32) -> i32, but the concrete type of that closure is not known at compile time. If you actually call the closure, the concrete type of the closure is determined at runtime, and the generated code dynamically dispatches to the right function. In this case, argument type and return type are the same type, so you can use a type alias if you want to:
type MyBoxedFn = Box<dyn Fn(i32) -> i32>;
fn hof_six(a: i32, func: MyBoxedFn) -> MyBoxedFn {
Box::new(move |v| func(a + v))
}
This is completely equivalent to the original version.
Not usefully, no, there is not.
To make something shorter, you generally have to reduce redundancy or remove characters.
There's no semantic redundancy because the argument and return type mean different things.
impl and fn and i32 are already abbreviated, so they can't have characters removed.
All that's left is textual similarities. You can use a macro to do that, but I don't think it's a good idea:
macro_rules! F {
() => (impl Fn(i32) -> i32);
}
fn hof_five(a: i32, func: F!()) -> F!() {
move |v| func(a + v)
}
See also:
What makes `impl Trait` as an argument "universal" and as a return value "existential"?
You might also be interested in using where clauses to spread out the complexity:
fn hof_five<F>(a: i32, func: F) -> impl Fn(i32) -> i32
where
F: Fn(i32) -> i32,
{
move |v| func(a + v)
}
How can I reduce the lifetime of a closure?
I was trying to make a method, which returns an iterator related to self. I didn't want to make new struct or something, so I just made it return filters and maps, and confronted some borrow checker errors.
The following code was my first try.
fn f<'b>(&'b self) -> impl Iterator<Item = u8> {
(0..self.some_number())
.filter(|&i| self.some_bool_function(i))
.map(|i| i as u8)
}
The following code replicates my question.
struct A(bool);
impl A {
fn f<'a>(&'a self) -> impl Iterator<Item = u8> + 'a {
(0..1).filter(|&i| self.0)
}
}
or even shorter,
fn g<'a>(t:&'a ()) -> impl 'a + FnMut() {
|| *t
}
This would not compile, because the closure may outlive self. I don't know how to make this work, without moving self.
If you return a closure, you must ensure that the closure has everything it needs - even after returning (i.e. after the (temporary) function parameters are popped from the stack).
Thus, I think you want to move the stuff you return into the closure:
impl A {
fn f<'a>(&'a self) -> impl Iterator<Item = u8> + 'a {
(0..1).filter(move |&i| self.0)
}
}
Resp.
fn g<'a>(t:&'a ()) -> impl 'a + FnMut() {
move || *t
}
Resp (extending your first example):
struct A(bool);
impl A {
fn some_number(&self) -> usize {
6
}
fn some_bool_function(&self, i: usize) -> bool {
i%2==0
}
fn f<'b>(&'b self) -> impl Iterator<Item = u8> + 'b {
(0..self.some_number())
.filter(move |&i| self.some_bool_function(i))
.map(|i| i as u8)
}
}
Can I pass a function as a parameter? If not, what is a good alternative?
I tried some different syntaxes but I have not found the right one. I know I can do this:
fn example() {
let fun: fn(value: i32) -> i32;
fun = fun_test;
fun(5i32);
}
fn fun_test(value: i32) -> i32 {
println!("{}", value);
value
}
but that's not passing the function as a parameter to another function:
fn fun_test(value: i32, (some_function_prototype)) -> i32 {
println!("{}", value);
value
}
Sure you can:
fn fun_test(value: i32, f: &dyn Fn(i32) -> i32) -> i32 {
println!("{}", f(value));
value
}
fn times2(value: i32) -> i32 {
2 * value
}
fn main() {
fun_test(5, ×2);
}
As this is Rust, you have to take into account the ownership and lifetime of the closure.
TL;DR; Basically there are 3 types of closures (callable objects):
Fn: It cannot modify the objects it captures.
FnMut: It can modify the objects it captures.
FnOnce: The most restricted. Can only be called once because when it is called it consumes itself and its captures.
See When does a closure implement Fn, FnMut and FnOnce? for more details
If you are using a simple pointer-to-function like closure, then the capture set is empty and you have the Fn flavor.
If you want to do more fancy stuff, then you will have to use lambda functions.
In Rust there are proper pointers to functions, that work just like those in C. Their type is for example fn(i32) -> i32. The Fn(i32) -> i32, FnMut(i32) -> i32 and FnOnce(i32) -> i32 are actually traits. A pointer to a function always implements all three of these, but Rust also has closures, that may or may not be converted to pointers (depending on whether the capture set is empty) to functions but they do implement some of these traits.
So for example, the example from above can be expanded:
fn fun_test_impl(value: i32, f: impl Fn(i32) -> i32) -> i32 {
println!("{}", f(value));
value
}
fn fun_test_dyn(value: i32, f: &dyn Fn(i32) -> i32) -> i32 {
println!("{}", f(value));
value
}
fn fun_test_ptr(value: i32, f: fn(i32) -> i32) -> i32 {
println!("{}", f(value));
value
}
fn times2(value: i32) -> i32 {
2 * value
}
fn main() {
let y = 2;
//static dispatch
fun_test_impl(5, times2);
fun_test_impl(5, |x| 2*x);
fun_test_impl(5, |x| y*x);
//dynamic dispatch
fun_test_dyn(5, ×2);
fun_test_dyn(5, &|x| 2*x);
fun_test_dyn(5, &|x| y*x);
//C-like pointer to function
fun_test_ptr(5, times2);
fun_test_ptr(5, |x| 2*x); //ok: empty capture set
fun_test_ptr(5, |x| y*x); //error: expected fn pointer, found closure
}
Fn, FnMut and FnOnce, outlined in the other answer, are closure types. The types of functions that close over their scope.
Apart from passing closures Rust also supports passing simple (non-closure) functions, like this:
fn times2(value: i32) -> i32 {
2 * value
}
fn fun_test(value: i32, f: fn(i32) -> i32) -> i32 {
println!("{}", f (value));
value
}
fn main() {
fun_test (2, times2);
}
fn(i32) -> i32 here is a function pointer type.
If you don't need a full-fledged closure than working with function types is often simpler as it doesn't have to deal with those closure lifetime nicities.
I'm trying to make two structs that operate on an underlying dataset; one providing immutable "read" operations, the other allowing modification. For this to work, I need to be able to use the read functions from within the modifying object - as such I create a temporary new read object within the modifier function with a view onto the underlying data.
Here's some code:
struct Read<'db> {
x: &'db i32
}
impl<'db> Read<'db> {
pub fn get(&'db self) -> &'db i32 { self.x }
}
struct Write<'db> {
x: &'db mut i32
}
impl<'db> Write<'db> {
fn new(x: &mut i32) -> Write { Write{x: x} }
fn as_read(&'db self) -> Read<'db> {
Read{x: self.x}
}
pub fn get(&'db self) -> &'db i32 { self.as_read().get() }
}
fn main() {
let mut x = 69i32;
let y = Write::new(&mut x);
println!("{}", y.get());
}
It doesn't compile - it seems that despite my best efforts, the lifetime of the reference returned from Read::get is bound to the Write::get's scope, rather than the Write's 'db lifetime. How can I make it compile? (And, is what I want to do possible? Is it the simplest/most concise way of doing it?)
The point the compiler is trying to get across is that &'db self actually means self: &'db Write<'db>. This means that you tie the reference AND the type to the same lifetime. What you actually want in your case is self: &'a Write<'db> where 'a lives just for the as_read function. To be able to return a 'db reference from a 'a reference, you need to specify that 'a lives at least as long as 'db by constraining 'a: 'db.
fn as_read<'a: 'db>(self: &'a Write<'db>) -> Read<'db> {
Read{x: self.x}
}
pub fn get<'a: 'db>(self: &'a Write<'db>) -> &'db i32 { self.as_read().get() }
or more concisely
fn as_read<'a: 'db>(&'a self) -> Read<'db> {
Read{x: self.x}
}
pub fn get<'a: 'db>(&'a self) -> &'db i32 { self.as_read().get() }
Try it out in the Playground
I'm trying to use a for loop to iterate over a vector of functions and execute each function at each step.
fn f1(i: i32) -> i32 {
i * 2
}
fn f2(i: i32) -> i32 {
i * 4
}
fn main() {
let mut arr: Vec<|i32| -> i32> = Vec::new();
arr.push(f1);
arr.push(f2);
for f in arr.iter() {
println!("{}", f(1));
}
}
But the attempted execution of f(1) gives this error:
error: expected function, found '&|i32| -> i32'
I guess in putting the functions in the vector their type is mutated and no longer works like a normal function. Is there a way to transform it back, or am I missing something?
As of Rust 1.x, unboxed closures are the only kind of closures in the language, and they don't need a feature flag. Moreover, static functions can easily be converted to unboxed closures. Therefore, the correct way to call functions from a vector of functions is:
fn f1(i: i32) -> i32 { i * 2 }
fn f2(i: i32) -> i32 { i * 4 }
fn main() {
let arr: Vec<&dyn Fn(i32) -> i32> = vec![&f1, &f2];
for f in &arr {
println!("{}", (f)(1));
}
}
I've used Fn() closures which can access their environment through a shared reference, so it is sufficient to iterate the vector by reference. If I had used a FnMut() closure, I would have had to use iteration by mutable reference:
fn f1(i: i32) -> i32 { i * 2 }
fn f2(i: i32) -> i32 { i * 4 }
fn main() {
let p1 = &mut f1;
let p2 = &mut f2;
let mut arr: Vec<&mut dyn FnMut(i32) -> i32> = vec![p1, p2];
for f in &mut arr {
println!("{}", (f)(1));
}
}
A similar idea holds for FnOnce() and iteration by value, although here we need to use Box to own the closure:
fn f1(i: i32) -> i32 { i * 2 }
fn f2(i: i32) -> i32 { i * 4 }
fn main() {
let arr: Vec<Box<dyn FnOnce(i32) -> i32>> = vec![Box::new(f1), Box::new(f1)];
for f in arr {
println!("{}", (f)(1));
}
}
Alternatively, if you know that you only work with static functions, it is possible to store pointers to them directly, without using closure traits:
fn f1(i: i32) -> i32 { i * 2 }
fn f2(i: i32) -> i32 { i * 4 }
fn main() {
let arr: Vec<fn(i32) -> i32> = vec![f1, f2];
for f in &arr {
println!("{}", (f)(1));
}
}
While f1 and f2 actually have different incompatible types, they are automatically coerced to the general function pointer type fn(i32) -> i32 when used in appropriate context, like in the example above.
Because static functions don't have any environment, you can freely clone references to them and call them through any kind of reference. This is probably the way to go if you only need static functions.
This answer was updated for Rust 1.x; older versions of the answer remain in the edit history.