- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
此代码是一种从迭代器生成唯一项集的低效方式。为此,我尝试使用 Vec
跟踪我看到的值。我相信这个Vec
需要由最里面的闭包拥有:
fn main() {
let mut seen = vec![];
let items = vec![vec![1i32, 2], vec![3], vec![1]];
let a: Vec<_> = items
.iter()
.flat_map(move |inner_numbers| {
inner_numbers.iter().filter_map(move |&number| {
if !seen.contains(&number) {
seen.push(number);
Some(number)
} else {
None
}
})
})
.collect();
println!("{:?}", a);
}
error[E0507]: cannot move out of captured outer variable in an `FnMut` closure
--> src/main.rs:8:45
|
2 | let mut seen = vec![];
| -------- captured outer variable
...
8 | inner_numbers.iter().filter_map(move |&number| {
| ^^^^^^^^^^^^^^ cannot move out of captured outer variable in an `FnMut` closure
最佳答案
这有点令人惊讶,但不是错误。
flat_map
需要一个 FnMut
因为它需要多次调用闭包。带有 move
的代码内部闭包失败,因为该闭包被创建多次,每次创建一次 inner_numbers
.如果我以显式形式编写闭包(即存储捕获的结构和闭包特征之一的实现),您的代码看起来(有点)像
struct OuterClosure {
seen: Vec<i32>
}
struct InnerClosure {
seen: Vec<i32>
}
impl FnMut(&Vec<i32>) -> iter::FilterMap<..., InnerClosure> for OuterClosure {
fn call_mut(&mut self, (inner_numbers,): &Vec<i32>) -> iter::FilterMap<..., InnerClosure> {
let inner = InnerClosure {
seen: self.seen // uh oh! a move out of a &mut pointer
};
inner_numbers.iter().filter_map(inner)
}
}
impl FnMut(&i32) -> Option<i32> for InnerClosure { ... }
&mut OuterClosure
多变的。
seen
仅在闭包内被修改(未移动)。然而,事情太懒了,无法正常工作......
error: lifetime of `seen` is too short to guarantee its contents can be safely reborrowed
--> src/main.rs:9:45
|
9 | inner_numbers.iter().filter_map(|&number| {
| ^^^^^^^^^
|
note: `seen` would have to be valid for the method call at 7:20...
--> src/main.rs:7:21
|
7 | let a: Vec<_> = items.iter()
| _____________________^
8 | | .flat_map(|inner_numbers| {
9 | | inner_numbers.iter().filter_map(|&number| {
10| | if !seen.contains(&number) {
... |
17| | })
18| | .collect();
| |__________________^
note: ...but `seen` is only valid for the lifetime as defined on the body at 8:34
--> src/main.rs:8:35
|
8 | .flat_map(|inner_numbers| {
| ___________________________________^
9 | | inner_numbers.iter().filter_map(|&number| {
10| | if !seen.contains(&number) {
11| | seen.push(number);
... |
16| | })
17| | })
| |_________^
move
s 使闭包捕获像
struct OuterClosure<'a> {
seen: &'a mut Vec<i32>
}
struct InnerClosure<'a> {
seen: &'a mut Vec<i32>
}
impl<'a> FnMut(&Vec<i32>) -> iter::FilterMap<..., InnerClosure<??>> for OuterClosure<'a> {
fn call_mut<'b>(&'b mut self, inner_numbers: &Vec<i32>) -> iter::FilterMap<..., InnerClosure<??>> {
let inner = InnerClosure {
seen: &mut *self.seen // can't move out, so must be a reborrow
};
inner_numbers.iter().filter_map(inner)
}
}
impl<'a> FnMut(&i32) -> Option<i32> for InnerClosure<'a> { ... }
&mut self
生命周期。)
FilterMap
迭代器在内部存储闭包,这意味着闭包值中的任何引用(即它捕获的任何引用)都必须是有效的,只要
FilterMap
值被抛出,并且,对于
&mut
引用,任何引用都必须小心不要出现锯齿。
flat_map
不会,例如将所有返回的迭代器存储在
Vec<FilterMap<...>>
中这会导致一堆别名
&mut
s……很糟糕!我觉得这个具体用途
flat_map
碰巧是安全的,但我不确定它是否一般,并且肯定有与
flat_map
具有相同签名风格的函数(例如
map
)肯定是
unsafe
. (实际上,在代码中用
flat_map
替换
map
给出了我刚刚描述的
Vec
情况。)
self
有效(忽略结构包装器)
&'b mut (&'a mut Vec<i32>)
哪里
'b
是
&mut self
的生命周期引用和
'a
是
struct
中引用的生命周期.搬家
&mut
out 是非法的:不能移动像
&mut
这样的仿射类型出于引用(尽管它可以与
&Vec<i32>
一起使用),因此唯一的选择是重新借用。重新借用正在通过外部引用,因此不能超过它,即
&mut *self.seen
再借是
&'b mut Vec<i32>
,不是
&'a mut Vec<i32>
.
InnerClosure<'b>
,因此
call_mut
方法试图返回
FilterMap<..., InnerClosure<'b>>
.不幸的是,
the FnMut
trait定义
call_mut
就像
pub trait FnMut<Args>: FnOnce<Args> {
extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
}
self
的生命周期之间没有联系。引用自身和返回值,因此尝试返回
InnerClosure<'b>
是非法的有那个链接。这就是编译器提示生命周期太短而无法重新借用的原因。
Iterator::next
极为相似方法,并且这里的代码失败的原因基本上与不能有迭代器对迭代器本身拥有的内存的引用相同。 (我想象一个
"streaming iterator"(在
&mut self
和
next
中的返回值之间有一个链接的迭代器)库将能够提供一个
flat_map
可以与几乎编写的代码一起使用:需要“闭包”特征类似的链接。)
RefCell
由 Renato Zannon 建议,允许 seen
作为共享借用&
.除了更改 &mut Vec<i32>
之外,脱糖关闭代码基本相同至 &Vec<i32>
.此更改意味着“重新借用”&'b mut &'a RefCell<Vec<i32>>
可以只是&'a ...
的副本出了&mut
.这是一个文字副本,因此保留了生命周期。 .collect::<Vec<_>>()
在循环内部运行以贯穿整个 filter_map
在回来之前。 fn main() {
let mut seen = vec![];
let items = vec![vec![1i32, 2], vec![3], vec![1]];
let a: Vec<_> = items
.iter()
.flat_map(|inner_numbers| {
inner_numbers
.iter()
.filter_map(|&number| if !seen.contains(&number) {
seen.push(number);
Some(number)
} else {
None
})
.collect::<Vec<_>>()
.into_iter()
})
.collect();
println!("{:?}", a);
}
RefCell
版本效率更高。
关于closures - 如何将捕获的变量移动到闭包内的闭包中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57391311/
我在一个简单的 GTK 应用程序中有两个小部件: extern crate gdk; extern crate gtk; use super::desktop_entry::DesktopEntry;
我想做这样的事情: const vegetableColors = {corn: 'yellow', peas: 'green'}; const {*} = vegetableColors; cons
该属性它存储在 gradle 中的什么位置? subprojects { println it.class.name // DefaultProject_Decorated depen
我想在 jQuery 闭包中看到窗口属性“otherName”描述符。但 进入 jQuery 闭包 'otherName' 描述符显示未定义,我认为可能 是 getOwnPropertyDescrip
我曾经看过 Douglas Crockford 的一次演讲,在 javascript 的上下文中,他提到将 secret 存储在闭包中可能很有用。 我想这可以在 Java 中像这样天真地实现: pub
我很难理解 Swift 中闭包中真正发生的事情,希望有人能帮助我理解。 class MyClass { func printWhatever(words: String) {
我有两个 3 表:用户、个人资料、friend_request $my_profile_id变量存储用户个人资料ID的值 $my_user_id = Auth::user()->id; $my_pro
我正在尝试通过使用 GLFW 的包装来学习 Swift GLFW 允许添加错误回调: GLFWAPI GLFWerrorfun glfwSetErrorCallback(GLFWerrorfun cb
我是一名优秀的程序员,十分优秀!