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
现在位于闭包内,因此不会编译):

我可以通过在闭包外部定义一个helper
new\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
实现:(是的,它很难看。我希望
新建右节点=右节点;
中的
拖放将在
新建右节点
初始化为
无时得到优化。