I have a problem trying to implement a callback to filter method in Rust. I have this function:
fn filter_by_mod(num: i32) -> fn(x: &i32) -> bool {
let func = |x: &i32| {
x.to_owned() % num == 0
};
return func;
}
I am trying to filter by mod and I would like to pass the number by paramenter and use in the func clousure, but when I try to compile I have the following error:
fn filter_by_mod(num: i32) -> fn(x: &i32) -> bool {
| ------------------- expected `for<'r> fn(&'r i32) -> bool` because of return type
9 | let func = |x: &i32| {
| ________________-
10 | | x.to_owned() % num == 0
11 | | };
| |_____- the found closure
12 | return func;
| ^^^^ expected fn pointer, found closure
|
= note: expected fn pointer `for<'r> fn(&'r i32) -> bool`
found closure `[closure#.\main.rs:9:16: 11:6]`
note: closures can only be coerced to `fn` types if they do not capture any variables
--> .\main.rs:10:24
|
10 | x.to_owned() % num == 0
| ^^^ `num` captured here
error: aborting due to previous error
How I can pass the number to func scope? I hope that you can understandme, because my english is not good. Thanks.
There are 2 problems why the example does not compile:
You are returning fn type. In rust it is a function pointer, but a closure is not a function, so you need to return an implementation of Fn trait.
But default closure borrows the context parameters, so you need to move it:
fn filter_by_mod(num: i32) -> impl Fn(&i32) -> bool {
let func = move |x: &i32| {
x.to_owned() % num == 0
};
return func;
}
Two things happening here:
You need to move num into the new function
Your function signature is wrong, you cannot return a function pointer, you need to use impl + function trait signature needed.
With minor stylish adjustments too:
fn filter_by_mod(num: i32) -> impl Fn(&i32) -> bool {
move |x: &i32| {
x.to_owned() % num == 0
}
}
Playground
Related
This question already has answers here:
Dynamically select a function to call without intermediate variables
(2 answers)
Closed 10 months ago.
I am trying to create a method that takes an Option<impl Fn() -> ()> as a parameter, and, if this parameter is Some(func), stores func as a closure, but, if it is None, stores some default function as the closure. Specifically, my code is as follows:
fn foo()
{
println!("HI");
}
fn bar(baz: Option<impl Fn () -> ()>)
{
let func = match baz {
Some(func) => func,
//None => foo,
None => unimplemented!()
};
func();
}
pub fn main() {
bar(Some(foo));
}
As-is, the code compiles, which indicates to me that foo is indeed something that should work with impl Fn () -> (). However, if I swap out the None arm of my match with the commented out None arm to set foo as my "default implentation", I get the following error:
error[E0308]: `match` arms have incompatible types
--> <source>:10:17
|
6 | fn bar(baz: Option<impl Fn () -> ()>)
| ---------------- this type parameter
7 | {
8 | let func = match baz {
| ________________-
9 | | Some(func) => func,
| | ---- this is found to be of type `impl Fn() -> ()`
10 | | None => foo,
| | ^^^ expected type parameter `impl Fn() -> ()`, found fn item
11 | | //None => unimplemented!()
12 | | };
| |_____- `match` arms have incompatible types
|
= note: expected type `impl Fn() -> ()`
found fn item `fn() {foo}`
error: aborting due to previous error
As far as I can tell from the error, it is saying that foo does not qualify as impl Fn() -> () within the function (though it did when passed in as a parameter). What am I missing here that causes this, and is there a way to accomplish what I want here (take an optional closure as a parameter, and use a default function as a closure if none provided)?
All the arms of a match statement must resolve to the exact same type.
With that in mind, let's replace impl Fn() -> () (which is also the same as impl Fn() BTW) with the generics that it represents:
fn bar<T>(baz: Option<T>) where T: Fn() {
// ...
}
impl Trait (in a function parameter) is syntactic sugar for regular generics, so this is "what the compiler sees".
Then let's look at the match:
fn bar<T>(baz: Option<T>) where T: Fn() {
let f = match baz {
Some(f) => f,
None => foo,
};
}
This can't work, because the type of foo is a special thing called a "function item" (essentially a unique type), but the type of f is a generic parameter T: it could be any type imaginable (as long as it implements Fn()). Clearly, these might be different, so Rust rejects the match statement as "having incompatible types".
What you're looking for is a trait object (though this comes at the cost of a heap allocation and vtable dispatch):
fn bar(baz: Option<impl Fn()>) {
let f: Box<dyn Fn()> = match baz {
Some(f) => Box::new(f),
None => Box::new(foo),
};
f();
}
Or, you can call the function immediately without storing in a variable:
fn bar(baz: Option<impl Fn()>) {
match baz {
Some(f) => f(),
None => foo(),
};
}
This is likely to be faster than the dyn Fn() approach above, though of course, if you are later storing it in a struct, this will not work.
I have this simple struct with 2 Hashsets:
pub struct IpAddresses {
pub ipv4s: HashSet<String>,
pub ipv6s: HashSet<String>,
}
and then a simple function which is supposed to provide an iterator to one of the sets:
pub fn shared2(&self, ipv6: bool) -> impl Iterator<Item = IpAddr> + '_ {
if ipv6 {
self
.ipv6s
.iter()
.filter_map(|a| IpAddr::from_str(a).ok())
} else {
self
.ipv4s
.iter()
.filter_map(|a| IpAddr::from_str(a).ok())
}
}
I get the following error with the suggestion to use box:
error[E0308]: `if` and `else` have incompatible types
--> src/models/ip_address.rs:131:13
|
125 | / if ipv6 {
126 | | self
| _|_____________-
127 | | | .ipv6s
128 | | | .iter()
129 | | | .filter_map(|a| IpAddr::from_str(a).ok())
| |_|_____________________________________________________- expected because of this
130 | | } else {
131 | / | self
132 | | | .ipv4s
133 | | | .iter()
134 | | | .filter_map(|a| IpAddr::from_str(a).ok())
| |_|_____________________________________________________^ expected closure, found a different closure
135 | | }
| |_________- `if` and `else` have incompatible types
|
= note: expected type `FilterMap<std::collections::hash_set::Iter<'_, _>, [closure#src/models/ip_address.rs:129:25: 129:53]>`
found struct `FilterMap<std::collections::hash_set::Iter<'_, _>, [closure#src/models/ip_address.rs:134:25: 134:53]>`
= note: no two closures, even if identical, have the same type
= help: consider boxing your closure and/or using it as a trait object
help: you could change the return type to be a boxed trait object
|
122 | pub fn shared2(&self, ipv6: bool) -> Box<dyn Iterator<Item = IpAddr> + '_> {
| ~~~~~~~ +
help: if you change the return type to expect trait objects, box the returned expressions
|
126 ~ Box::new(self
127 | .shared_ipv6s
128 | .iter()
129 ~ .filter_map(|a| IpAddr::from_str(a).ok()))
130 | } else {
131 ~ Box::new(self
Interestingly enough if I copy paste one of the wings into a function, the compiler works fine without any error or need for a Box:
fn list_shared<'a>(&'a self, items: &'a HashSet<String>) -> impl Iterator<Item = IpAddr> + 'a {
items
.iter()
.filter_map(|a| IpAddr::from_str(a).ok())
}
pub fn shared<'a>(&'a self, ipv6: bool) -> impl Iterator<Item = IpAddr> + 'a {
if ipv6 {
self.list_shared(&self.ipv6s)
} else {
self.list_shared(&self.ipv4s)
}
}
As you can see this is a copy-paste of the inner block. Why is this happening? How are those 2 identical blocks not identical in the first instance but just putting them inside a function made them identical?
Each closure gets its own, anonymous type. Even though the closures have the same call signature, and even if neither of them borrows anything so no lifetimes are part of the signature, these types are not the same!
Therefore, the generic <F> in the returned FilterMap struct has a different type in each if branch, leading to the error message about trying to return incompatible types.
Note that -> impl Iterator tells the compiler that you're returning some type that implements Iterator, but it has to be statically the same type every time, determined at compile time.
When you extract the filter_map call to a separate function, there is only one closure, hence one type returned from that function. And since this is the same type for both if branches, the problem goes away.
It also goes away if you assign the closure to a variable, because then it's the same type in both cases as well:
pub fn shared2(&self, ipv6: bool) -> impl Iterator<Item = IpAddr> + '_ {
let from_str = |a: &String| IpAddr::from_str(a).ok();
if ipv6 {
self
.ipv6s
.iter()
.filter_map(from_str)
} else {
self
.ipv4s
.iter()
.filter_map(from_str)
}
}
impl Iterator<Item=IpAddr> is saying 'this function will return a static type that is determined at runtime that conforms to Iterator<Item=IpAddr>.
It is not the same as Box<dyn Iterator<Item=IpAddr> which means any type that conforms to Iterator<Item=IpAddr>.
The reason it dosent work is because each each one of |a| IpAddr::from_str(a).ok()) are diffrent types that are generated by the compiler, and filter_map rerurns a struct that has the iterator of the type FilterMap<I, F>, with F being the type of the function.
You can see the same issue if you move your closures to named functions
fn ipv6_iter(a: &String) -> Option<IpAddr> {
IpAddr::from_str(a).ok()
}
fn ipv4_iter(a: &String) -> Option<IpAddr> {
IpAddr::from_str(a).ok()
}
impl IpAddresses {
pub fn shared2(&self, ipv6: bool) -> impl Iterator<Item = IpAddr> + '_ {
if ipv6 {
self
.ipv6s
.iter()
.filter_map( ipv6_iter)
} else {
self
.ipv4s
.iter()
.filter_map( ipv4_iter)
}
}
}
In your first branch returns a FilterMap<IpAddresses, ipv6_iter>, but the else branch returns a FilterMap<IpAddresses, ipv4_iter>.
By moving the logic into list_shared, both filter_maps use the same anonymous function to do the mapping, therefore have the same FilterMap type.
Same as using the same static function in each filter_map
fn ip_iter(s: &String) -> Option<IpAddr> {
IpAddr::from_str(s).ok()
}
impl IpAddresses {
pub fn shared2(&self, ipv6: bool) -> impl Iterator<Item = IpAddr> + '_ {
if ipv6 {
self
.ipv6s
.iter()
.filter_map( ip_iter)
} else {
self
.ipv4s
.iter()
.filter_map( ip_iter)
}
}
}
So each branch returns a FilterMap<IpAddresses, ip_iter>, therefore impl Iterator<Item=IpAddr> has a single type to resolve to.
I'm trying to write a function, that takes a closure and returns back whatever the closures return type is. I don't want hard-coded return types, like in fn(action: &dyn Fn()) -> i32. I tried to solve it as you can see below:
pub fn execute_code<T>(actions: T) -> T::Output
where
T: Fn(),
{
println!("before:");
let res = actions();
println!("after:");
res
}
fn main() {
let i32_res: i32 = execute_code(&|| 5 + 5);
let str_res: &str = execute_code(&|| "a string");
println!("i32_res: {}, string_res: {}", i32_res, str_res);
}
But the compiler (1.53 stable) complains about:
pub fn execute_code<T>(actions: T) -> T::Output
| ------------ required by a bound in this
2 | where
3 | T: Fn(),
| ---- required by this bound in `execute_code`
...
12 | let i32_res: i32 = execute_code(&|| 5 + 5);
| ^^^^^^^^^^^^ expected `()`, found integer
What is the right way to achieve this?
You just need to parametrize the output as another type:
pub fn execute_code<T, R>(actions: T) -> R
where
T: Fn() -> R,
{
println!("before:");
let res = actions();
println!("after:");
res
}
fn main() {
let i32_res: i32 = execute_code(&|| 5 + 5);
let str_res: &str = execute_code(&|| "a string");
println!("i32_res: {}, string_res: {}", i32_res, str_res);
}
Playground
I have many functions of the following type signature:
fn f() -> impl Fn(u32) -> u32 {
|x: u32| x
}
How can I give a name to Fn(u32) -> u32 so that I don't have to repeat it? Although I can do type X = Fn(u32) -> u32;, Rust will not let me use this because it is a type and not a trait. Must I wait for trait_alias or can I do something else?
You're exactly right. impl X requires X to be a trait, and it's impossible to have proper trait aliases until trait aliases land. When that happens you'll be able to do this:
#![feature(trait_alias)]
trait X = Fn(u32) -> u32;
fn f() -> impl X {
|x: u32| x
}
(playground)
Alternatively, when Permit impl Trait in type aliases lands, you'll be able to make impl trait a type alias. This is slightly different though. When we alias with type X = impl Trait, the compiler will ensure that every usage of X is actually the same concrete type. That would mean that, in your case, you wouldn't be able to use this with multiple different closures, since every closure has its own unique type.
#![feature(type_alias_impl_trait)]
type X = impl Fn(u32) -> u32;
fn f() -> X {
|x: u32| x
}
(playground)
However, this won't compile.
#![feature(type_alias_impl_trait)]
type X = impl Fn(u32) -> u32;
fn f() -> X {
|x: u32| x
}
// Even a closure with exactly the same form has a different type.
fn g() -> X {
|x: u32| x
}
The error is
error: concrete type differs from previous defining opaque type use
--> src/lib.rs:10:1
|
10 | / fn g() -> X {
11 | | |x: u32| x
12 | | }
| |_^ expected `[closure#src/lib.rs:7:5: 7:15]`, got `[closure#src/lib.rs:11:5: 11:15]`
|
note: previous use here
--> src/lib.rs:6:1
|
6 | / fn f() -> X {
7 | | |x: u32| x
8 | | }
| |_^
(playground)
This is in contrast to trait aliases, which would allow a different concrete type to be used with every function returning impl TraitAlias. See the RFCs that introduced this syntax and existential types in general for more.
Until one of those two features lands, you can get similar behavior to the trait alias with what is essentially a hack. The idea is to make a new trait which is essentially equivalent to the original trait, but has a shorter name.
// This trait is local to this crate,
// so we can implement it on any type we want.
trait ShortName: Fn(u32) -> u32 {}
// So let's go ahead and implement `ShortName`
// on any type that implements `Fn(u32) -> u32`.
impl<T: Fn(u32) -> u32> ShortName for T {}
// We can use `ShortName` to alias `Fn(u32) -> u32`.
fn f() -> impl ShortName {
|x: u32| x
}
// Moreover, the result of that can be used in places
// that expect `Fn(u32) -> u32`.
fn g<T: Fn(u32) -> u32>(x: &T) -> u32 {
x(6_u32)
}
fn main() {
// We only know that `x` implements `ShortName`,
let x = f();
// But we can still use `x` in `g`,
// which expects an `Fn(u32) -> u32` argument
let _ = g(&x);
}
(playground)
tool is a grab-bag of useful functions for functional programming includes making recursive closure, for example:
extern crate tool;
use tool::prelude::*;
fn main() {
let fib = fix(move |f, x| {
if x == 0 || x == 1 {
x
} else {
// `f` is `fib`
f(x - 1) + f(x - 2)
}
});
println!("{}", fib(10)); // print 55
}
Things I want to implement is here : playground
Here's the overview: I'm defining a function A which take a function B as parameter, again the function B take function C as parameter. I need to call the function C in a new thread, In this case using &dyn keyword for the inner function gives me an error:
fn a(b: impl Fn(&dyn Fn() -> ()) -> ()) -> () {
// ...
}
error[E0277]: `dyn std::ops::Fn() ->()` cannot be shared between threads safely
I try the syntax like below, but this gives me an another error:
fn a(b: impl Fn(impl Fn() -> ()) -> ()) -> () {
// ...
}
error[E0666]: nested `impl Trait` is not allowed
--> src/main.rs:2:21
|
2 | fn a(b: impl Fn(impl Fn() -> ()) -> ()) -> () {
| --------^^^^^^^^^^^^^^^-------
| | |
| | nested `impl Trait` here
| outer `impl Trait`