我有一个带有 2 个哈希集的简单结构:
pub struct IpAddresses {
pub ipv4s: HashSet<String>,
pub ipv6s: HashSet<String>,
}
Run Code Online (Sandbox Code Playgroud)
然后是一个简单的函数,它应该为其中一个集合提供迭代器:
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())
}
}
Run Code Online (Sandbox Code Playgroud)
我收到以下关于使用框的建议的错误:
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
Run Code Online (Sandbox Code Playgroud)
有趣的是,如果我将其中一个翼复制粘贴到函数中,编译器可以正常工作,没有任何错误或不需要 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
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,这是内部块的复制粘贴。为什么会发生这种情况?为什么这两个相同的块在第一个实例中并不相同,但只是将它们放入一个函数中就使它们相同了?
每个闭包都有自己的匿名类型。即使闭包具有相同的调用签名,即使它们都没有借用任何东西,因此签名中没有生命周期,但这些类型并不相同!
<F>因此,返回的结构中的泛型FilterMap在每个分支中具有不同的类型if,从而导致有关尝试返回不兼容类型的错误消息。
请注意,-> impl Iterator告诉编译器您要返回某种实现 的类型Iterator,但每次它都必须是静态相同的类型,在编译时确定。
当您提取filter_map对单独函数的调用时,只有一个闭包,因此从该函数返回一种类型。由于这两个分支的类型相同if,因此问题就消失了。
如果将闭包分配给变量,它也会消失,因为在这两种情况下它的类型也相同:
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)
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
224 次 |
| 最近记录: |