我可以创建一个“不安全的闭包”吗?

7

我有一些代码,简化后看起来像:

fn foo() -> Vec<u8> {
    unsafe {
        unsafe_iterator().map(|n| wrap_element(n)).collect()
    }
}

这个迭代器会返回在底层数据改变时会失效的元素。遗憾的是,我不能像平常那样依赖 Rust 的 mut 机制(我在做一些...奇怪的事情)。

为了纠正这种不安全性,我一次性遍历整个迭代器,对每个元素进行复制(通过 wrap_element),然后将它们全部放入一个 Vec 中。这种方式有效是因为没有其他内容有机会修改底层数据。

代码目前可以正常工作,但由于我多次使用这种习惯用法,所以我想稍微简化一下我的代码:

fn zap<F>(f: F) -> Vec<u8>
    where F: FnOnce() -> UnsafeIter
{
    f().map(|n| wrap_element(n)).collect()
}

fn foo() -> Vec<u8> {
    zap(|| unsafe { unsafe_iterator() }) // Unsafe block
}

我对这种解决方案的问题在于调用unsafe_iterator是不安全的,而正是wrap_element/collect使其再次变得安全。代码结构根本没有传达出这一点。

我想以某种方式标记我的闭包为unsafe,然后由zap负责使其再次变得安全。

1个回答

4
无法创建与unsafe fn类似的unsafe闭包,因为闭包只是具有实现FnFnMut和/或FnOnce族特性的匿名类型。由于这些特性没有unsafe方法,因此不可能创建一个调用时unsafe的闭包。
您可以创建第二组带有unsafe方法的闭包特性,然后编写这些特性的实现,但这将损失大部分闭包语法糖。

创建一组新的特质是一个有趣的想法!我猜这种语法糖与编译器紧密相关,作为终端用户,我无法将其用于新的特质,对吗? - Shepmaster
你可能可以像全局实现新特性一样实现旧特性,这样你就可以从闭包语法隐式地“转换”到不安全的特性。你仍然无法获得函数调用语法,但我认为这是一个很好的权衡。 - reem
我尝试了一下这个(http://is.gd/OgyWaO),但它并没有像它本应该那样有用。问题在于,当我们在闭包中“调用”不安全的fn时,编译器仍然会抱怨,因为它不知道`unsafe`将被传递,所以没有使用语法糖的机会。 - Shepmaster

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接