对于只有一小部分代码实际上在做“不安全”事情的“不安全”函数,最佳实践是什么?

What are best practices for `unsafe` functions in which only a small part of the code is actually doing `unsafe` things?

在我正在开发的 crate 中,我有几个 unsafe 函数,由于 的原因,它们被标记为这样。在 unsafe 函数中,我可以执行 unsafe 操作,就好像完整的函数体被包裹在 unsafe { } 块中一样。

问题在于,在较大的函数中,只有一小部分函数体实际上在执行 unsafe 操作,而其余部分则在做完全安全的事情。通常,这种安全的东西甚至完全独立于 unsafe 代码。在这些较大的函数中,我想缩小unsafe操作的范围。原因应该很容易理解:我也不会仅仅因为可以就将我的完整代码库包装在 unsafe { } 块中。

不幸的是,unsafe 函数的行为 "invert" 没有 safe { } 块。如果有我会这样使用它:

unsafe fn my_function() {
    safe {
        // ... doing safe stuff ...

        unsafe {
            // ... doing `unsafe` stuff ...
        }

        // ... doing safe stuff ...
    }
}

但这是不可能的:在这些情况下缩小 unsafe 操作范围的最佳做法是什么?是否有解决此问题的既定技巧?

明确一点:这个问题不是讨论缩小unsafe范围是好是坏。我说我想做:这个问题是关于 如何 做以及什么解决方案(如果有的话)最常在实践中使用 . (如果你不明白我为什么要这样做,this RFC 是非常相关的。)

如果您想使用 unsafe 关键字来对所有不安全的操作进行分类,您可以通过将代码拆分为安全的私有函数来构造更准确的边界。我不确定它是否完全满足您 "best practice" 的要求,因为我不知道有任何大型项目使用该技术,但它会起作用:

// Document the assumptions of this unsafe function here
pub unsafe fn my_function() {
    my_internal_function()
}

// private
fn my_internal_function() {
    // ... doing safe stuff ...
    unsafe {
        // Document the assumptions of this unsafe block here
        // ... doing `unsafe` stuff ...
    }
    // ... doing safe stuff ...
}

如果您担心 "safe" 函数的存在实际上是不安全的,引入了意外被错误使用的风险,您可以嵌套这些私有函数,这样它们就不能在主函数之外调用不安全函数:

pub unsafe fn my_function() {
    fn my_internal_function() {
        // ... doing safe stuff ...
        unsafe {
            // Document the assumptions of this unsafe block here
            // ... doing `unsafe` stuff ...
        }
        // ... doing safe stuff ...
    }

    my_internal_function();    
}

毕竟,正确记录不安全代码的假设和注释是最重要的部分。这种技巧只有在您关注不安全行数的指标时才有用。