Reputation: 18089
I'm having troubles figuring out the type signature of the fn filter
function in following example.
The Node and Descendant definition is just there for syntax . It's not meant to do anything!
use std::iter::Filter;
#[derive(Clone)]
pub struct Node<'a> {
s: &'a str,
}
pub struct Descendants<'a>{
iter: Node<'a>
}
impl<'a> Iterator for Descendants<'a> {
type Item = Node<'a>;
fn next(&mut self) -> Option<Node<'a>> {
Some(Node {s: self.iter.s})
}
}
impl<'a> Node<'a> {
pub fn descendants(&self) -> Descendants<'a> {
Descendants{ iter: Node{s: self.s} }
}
pub fn filter(&self, criteria: &str) -> Filter<Descendants<'a>, fn(&'a Node<'a>)->bool > {
self.descendants()
.filter(|node| node.s == "meh")
}
}
fn main() {
let doc = Node{s: "str"};
}
The error I get is following:
<anon>:27:28: 27:34 error: the type of this value must be known in this context
<anon>:27 .filter(|node| node.s == "meh")
^~~~~~
<anon>:27:21: 27:43 error: mismatched types:
expected `fn(&Node<'_>) -> bool`,
found `[closure <anon>:27:21: 27:43]`
(expected fn pointer,
found closure) [E0308]
<anon>:27 .filter(|node| node.s == "meh")
^~~~~~~~~~~~~~~~~~~~~~
<anon>:27:14: 27:44 error: type mismatch: the type `fn(&Node<'_>) -> bool` implements the trait `core::ops::FnMut<(&Node<'_>,)>`, but the trait `for<'r> core::ops::FnMut<(&'r Node<'_>,)>` is required (expected concrete lifetime, found bound lifetime parameter ) [E0281]
<anon>:27 .filter(|node| node.s == "meh")
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<anon>:27:14: 27:44 error: type mismatch resolving `for<'r> <fn(&Node<'_>) -> bool as core::ops::FnOnce<(&'r Node<'_>,)>>::Output == bool`:
expected bound lifetime parameter ,
found concrete lifetime [E0271]
<anon>:27 .filter(|node| node.s == "meh")
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to 4 previous errors
playpen: application terminated with error code 101
When I as per this question Correct way to return an Iterator? I tried to replace pub fn filter(&self, criteria: &str) -> Filter<Descendants<'a>, fn(&'a Node<'a>)->bool >
with pub fn filter(&self, criteria: &str) -> ()
I get
<anon>:26:9: 27:44 error: mismatched types:
expected `()`,
found `core::iter::Filter<Descendants<'_>, [closure <anon>:27:21: 27:43]>`
What I'm supposed to replace closure
with?
Alternatively, if it's too hard and finicky to return a Filter
, how do I write the Wrapper
for fn filter()
return type?
Upvotes: 3
Views: 830
Reputation: 127911
I clearly remember that this was answered before a few times (I even wrote about it in an answer a few minutes before) but I can't find a link now, so here it goes.
The problem with your code is that you use a closure as filter()
argument:
.filter(|node| node.s == "meh")
Unboxed closures in Rust are implemented as anonymous types which, naturally, can't be named, so there is no way to write a signature of a function which returns an iterator which uses a closure. That's what the error message you're getting is about:
expected `fn(&Node<'_>) -> bool`,
found `[closure <anon>:27:21: 27:43]`
(expected fn pointer,
found closure) [E0308]
There are several ways around this, one of them is to use trait objects:
pub fn filter<'b>(&'b self, criteria: &'b str) -> Box<Iterator<Item=Node<'a>+'b>>
{
Box::new(self.descendants().filter(move |node| node.s == criteria))
}
Given that your closure has a non-empty environment, this is the only way for your code to work. If your closure didn't capture anything, you could use a static function whose type can be written out:
pub fn filter(&self) -> Filter<Descendants<'a>, fn(&Node<'a>) -> bool> {
fn filter_fn<'b>(node: &Node<'b>) -> bool {
node.s == "meh"
}
self.descendants().filter(filter_fn)
}
Upvotes: 7