Rust 如何提示FnOnce闭包将只执行一次,以避免;捕获可能未初始化的变量“;警告
我正在尝试实施和应用。我是这样实施的:Rust 如何提示FnOnce闭包将只执行一次,以避免;捕获可能未初始化的变量“;警告,rust,Rust,我正在尝试实施和应用。我是这样实施的: trait OptionExt<T> { #[inline] fn replace_with<F>(&mut self, f: F) where F: FnOnce(Option<T>) -> Option<T>; } impl<T> OptionExt<T> for Option<T> { #[inline]
trait OptionExt<T> {
#[inline]
fn replace_with<F>(&mut self, f: F)
where
F: FnOnce(Option<T>) -> Option<T>;
}
impl<T> OptionExt<T> for Option<T> {
#[inline]
fn replace_with<F>(&mut self, f: F)
where
F: FnOnce(Option<T>) -> Option<T>,
{
let mut x = f(self.take());
mem::swap(self, &mut x);
debug_assert!(x.is_none());
mem::forget(x);
}
}
优化的实现():
优化的实施,具有更好的界面:
lower_node.right.replace_with(|node| merge(node, Some(greater_node));
当我想要实现一个将返回一对节点的
split_binary
函数时,这就不能很好地发挥作用:
简单实现:
let merged = merge(lower_node.right.take(), Some(greater_node));
lower_node.right = merged;
let (left_node, right_node) = split_binary(orig_node.right.take(), value);
orig_node.right = left_node;
(Some(orig_node), right_node)
let (mut left_node, right_node) = split_binary(orig_node.right.take(), value);
mem::swap(&mut orig_node.right, &mut left_node);
debug_assert!(left_node.is_none());
mem::forget(left_node);
(Some(orig_node), right_node)
优化实施:
let merged = merge(lower_node.right.take(), Some(greater_node));
lower_node.right = merged;
let (left_node, right_node) = split_binary(orig_node.right.take(), value);
orig_node.right = left_node;
(Some(orig_node), right_node)
let (mut left_node, right_node) = split_binary(orig_node.right.take(), value);
mem::swap(&mut orig_node.right, &mut left_node);
debug_assert!(left_node.is_none());
mem::forget(left_node);
(Some(orig_node), right_node)
具有更好界面的优化实现(由于right\u node
现在位于闭包内,因此不会编译):
我可以通过在闭包外部定义一个helpernew\u right\u节点来编译它:
orig_node.right.replace_with(|node| {
let (left_node, right_node) = split_binary(node, value);
left_node
});
(Some(orig_node), right_node)
let mut new_right_node = None;
orig_node.right.replace_with(|node| {
let (left_node, right_node) = split_binary(node, value);
new_right_node = right_node;
left_node
});
(Some(orig_node), new_right_node)
我必须用None
初始化new\u right\u节点
,否则Rust会出现错误“使用可能未初始化的new\u right\u节点
”。但是,执行此初始化会导致不必要的core::ptr::drop_in_place
调用new_right_节点的初始None
值。手动将replace_内联为
,无需预先初始化new_right_节点
:
let new_right_node;
{
let (mut left_node, right_node) = split_binary(orig_node.right.take(), value);
new_right_node = right_node;
mem::swap(&mut orig_node.right, &mut left_node);
debug_assert!(left_node.is_none());
mem::forget(left_node);
}
(Some(orig_node), new_right_node)
因此,如果我能说服Rust将执行闭包,从而初始化新的右节点,那么我似乎可以有效地解决这个问题
如何有效地解决此问题?您可以使用不安全
,因为您知道该值将始终初始化。两个unsafe
函数开始发挥作用:,它禁用“可能未初始化”错误,并允许您写入new\u right\u节点
,而不删除以前的(未初始化)值
我相信这在没有恐慌的情况下是安全的,因为新的\u right\u节点
总是被初始化,并且right\u节点
被移动到其中而没有任何一个被丢弃。但是,为了使其安全,您还必须保证,如果split\u binary
panics,则无法观察new\u right\u节点处于未初始化状态。谢谢您的建议!不幸的是,为了使API看起来更好,我不得不从稍微棘手的mem::*
调用unsafe
实现:(是的,它很难看。我希望新建右节点=右节点;
中的拖放将在新建右节点
初始化为无时得到优化。