何时将特征标记为不安全,而不是将特征中的所有功能标记为不安全?

时间:2015-07-25 16:21:36

标签: rust traits

在代码中说同样的事情,我何时会选择以下任何一个示例?

unsafe trait MyCoolTrait {
    fn method(&self) -> u8;
}

trait MyCoolTrait {
    unsafe fn method(&self) -> u8;
}

opt-in builtin traits (OIBIT) RFC州:

  

不安全的特征是一种不安全的特性,因为它代表了某种可信的断言。请注意,不安全的特性使用起来非常安全。 SendShare注意:现在称为Sync )是不安全特征的示例:实现这些特征实际上是一种断言,即您的类型对于线程是安全的。

标准库Searcher中还有另一个不安全特征的例子。它说:

  

该特征被标记为不安全,因为next()方法返回的索引需要位于大海捞针中有效的utf8边界。这使得该特征的消费者能够在没有额外运行时检查的情况下对大海捞针进行切片。

不幸的是,这些段落都没有真正帮助我理解何时将整个特征标记为不安全而不是某些或所有方法是正确的。

之前

I've asked about marking a function as unsafe,但这似乎有所不同。

2 个答案:

答案 0 :(得分:13)

一个函数标记为unsafe,表示可以通过调用来违反内存安全性。特征标记为unsafe,表示可以通过实现来违反内存安全性。这通常是因为特征具有其他不安全代码依赖于维护的不变量,并且这些不变量不能以任何其他方式表达

对于Searcher,方法本身应该可以安全地调用。也就是说,用户不应该担心他们是否正确使用Searcher;接口合同说所有电话都是安全的。你无能为力会导致这些方法违反记忆安全。

然而,不安全的代码会调用Searcher的方法,而这种不安全的代码将依赖给定的Searcher实现返回有效UTF-8代码点边界的偏移量。如果违反了这个假设,那么不安全的代码最终可能会导致内存安全违规。

换句话说:使用Searcher s 的不安全代码的正确性取决于每个Searcher实现 正确的。或者:错误地实现此特征允许安全代码诱导内存安全违规是无关的unsafe代码。

那么为什么不标记方法unsafe?因为他们根本不是不安全的!他们不会任何可能违反记忆安全的事情。 next_match只扫描并返回Option<(usize, usize)>。只有当不安全的代码假定这些usize是被搜索字符串的有效索引时,才存在这种危险。

那么为什么不检查结果呢?因为那会慢一些。搜索代码想要快速,这意味着它希望避免冗余检查。但是这些检查不能在Searcher界面中表达...所以相反,整个特征被标记为unsafe,以警告任何实施它的人有额外条件必须得到尊重的代码中声明或强制执行。

还有SendSync:当你不应该违反(必要时)必须处理线程的代码的期望时,实现这些。允许您创建线程的代码是安全的,但只要SendSync 在他们所属的类型上实现合适的。

答案 1 :(得分:0)

经验法则如下:

  • 如果方法用户需要将方法调用包装在unsafe fn method()块中,请使用unsafe

  • 如果特征实现者需要unsafe trait MyTrait,请使用unsafe impl MyTrait

unsafe是Rust用户的提示:不安全的代码必须仔细编写。 关键是unsafe应该用作双重使用:当作者将特征/功能声明为不安全时,实现者/用户需要使用unsafe来实现/使用它。

当功能标记为unsafe时,表示用户需要仔细使用该功能。函数作者假设函数用户必须保留。

当特征标记为unsafe时,这意味着特征实现者需要仔细实现。特性要求实现者保持一定的假设。但是具有不安全特征的用户无法调用该特征中定义的方法。

例如,unsafe trait Searcher要求所有Searcher的实现在调用next时都应返回有效的utf8边界。并且所有实现都标记为unsafe impl Searcher,表示实现代码可能不安全。但是,作为Searcher的用户,您可以调用searcher.next()而无需将其包装在unsafe块中。