什么时候将 trait 标记为不安全,而不是将 trait 中的所有函数标记为不安全?
在代码中说同样的话,我什么时候会选择以下示例中的任何一个?
Saying the same thing in code, when would I pick either of the following examples?
unsafe trait MyCoolTrait {
fn method(&self) -> u8;
}
trait MyCoolTrait {
unsafe fn method(&self) -> u8;
}
不安全特征是实现不安全的特征,因为它代表某种可信的断言.请注意,使用 unsafe trait 是完全安全的.发送
和分享
(注意:现在称为 Sync
) 是不安全特征的示例:实现这些特征实际上是断言您的类型对于线程处理是安全的.
An unsafe trait is a trait that is unsafe to implement, because it represents some kind of trusted assertion. Note that unsafe traits are perfectly safe to use.
Send
andShare
(note: now calledSync
) are examples of unsafe traits: implementing these traits is effectively an assertion that your type is safe for threading.
标准库中还有一个不安全 trait 的例子,搜索者
.它说:
There's another example of an unsafe trait in the standard library, Searcher
. It says:
特征被标记为不安全,因为 next()
方法返回的索引需要位于 haystack 中的有效 utf8 边界上.这使此特征的使用者无需额外的运行时检查即可切开大海捞针.
The trait is marked unsafe because the indices returned by the
next()
methods are required to lie on valid utf8 boundaries in the haystack. This enables consumers of this trait to slice the haystack without additional runtime checks.
不幸的是,这些段落都没有真正帮助我理解何时将整个特征标记为不安全而不是部分或全部方法是正确的.
Unfortunately, neither of these paragraphs really help my understanding of when it is correct to mark the entire trait unsafe instead of some or all of the methods.
我之前询问过将函数标记为不安全的问题,但这似乎有所不同.
一个函数被标记为 unsafe
以表明调用它可能会违反内存安全.一个 trait 被标记为 unsafe
以表明它有可能通过实现它违反内存安全.这通常是因为 trait 具有其他不安全代码所依赖的不变量,并且这些不变量不能以任何其他方式表达.
A function is marked unsafe
to indicate that it is possible to violate memory safety by calling it. A trait is marked unsafe
to indicate that it is possible to violate memory safety by implementing it at all. This is commonly because the trait has invariants that other unsafe code relies on being upheld, and that these invariants cannot be expressed any other way.
对于Searcher
,方法本身应该可以安全调用.也就是说,用户不必担心他们是否正确使用了Searcher
;接口契约说所有调用都是安全的.您无法做任何事情来导致方法违反内存安全.
In the case of Searcher
, the methods themselves should be safe to call. That is, users should not have to worry about whether or not they're using a Searcher
correctly; the interface contract says all calls are safe. There's nothing you can do that will cause the methods to violate memory safety.
然而,不安全的代码会调用Searcher
的方法,而这种不安全的代码将依赖给定的Searcher
实现以返回位于有效 UTF-8 代码点边界上的偏移量.如果违反了这个假设,那么不安全的代码最终可能会导致内存安全违规.
However, unsafe code will be calling the methods of a Searcher
, and such unsafe code will be relying on a given Searcher
implementation to return offsets that are on valid UTF-8 code point boundaries. If this assumption is violated, then the unsafe code could end up causing a memory safety violation itself.
换句话说:使用Searcher
的不安全代码的正确性取决于每个Searcher
实现也em> 正确.或者:错误地实现此特征允许安全代码诱导内存安全违规是无关的unsafe
代码.
To put it another way: the correctness of unsafe code using Searcher
s depends on every single Searcher
implementation also being correct. Or: implementing this trait incorrectly allows for safe code to induce a memory safety violation is unrelated unsafe
code.
那么为什么不直接标记方法unsafe
?因为它们并不不安全!他们不会做任何可能违反内存安全的事情.next_match
只是扫描并返回一个 Option
.只有当不安全代码假定这些usize
是被搜索字符串的有效索引时,危险才存在.
So why not just mark the methods unsafe
? Because they aren't unsafe at all! They don't do anything that could violate memory safety in and of themselves. next_match
just scans for and returns an Option<(usize, usize)>
. The danger only exists when unsafe code assumes that these usize
s are valid indices into the string being searched.
那么为什么不检查结果呢?因为那会更慢.搜索代码要快速,这意味着它要避免冗余检查.但是这些检查不能在 Searcher
接口中表达......因此,整个 trait 被标记为 unsafe
以警告任何实现它的人有额外的条件 未在必须遵守的代码中声明或强制执行.
So why not just check the result? Because that'd be slower. The searching code wants to be fast, which means it wants to avoid redundant checks. But those checks can't be expressed in the Searcher
interface... so instead, the whole trait is flagged as unsafe
to warn anyone implementing it that there are extra conditions not stated or enforced in the code that must be respected.
还有 Send
和 Sync
:在您不应该违反(除其他外)必须处理线程的代码的期望时实现它们.允许您创建线程的代码是安全的,但仅只要 Send
和 Sync
在它们适合的类型.
There's also Send
and Sync
: implementing those when you shouldn't violates the expectations of (among other things) code that has to deal with threads. The code that lets you create threads is safe, but only so long as Send
and Sync
are only implemented on types for which they're appropriate.