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?