Vee*_*rac 6 generics traits type-safety rust
出于优化目的,我希望创建一个数据结构,将单个值存储在多个不同的位置.数据结构只允许通过不可变引用使用这些值,或者完全从数据结构中删除它们.
如何确保这对于通用类型是安全的?
为上下文提供一个微不足道(但有点不切实际)的示例,请考虑一个缓存最近使用的值的切片:
struct Pair<'a> {
values: &'a [T],
last_accessed: &'a T,
}
Run Code Online (Sandbox Code Playgroud)
但是,访问最后访问的元素仍然会引发指针取消引用,因此代码需要按值缓存:
struct Pair<'a> {
values: &'a [T],
last_accessed: NoDrop<T>,
}
Run Code Online (Sandbox Code Playgroud)
在大多数情况下,这似乎是安全的.例如,如果T是a u32,则缓存只是数据的简单副本.
即使T是a Vec<U>,这似乎是安全的,因为任何访问&last_accessed都不能改变向量的任何直接成员.堆分配是可传递的,不会重复,因此没有明显的别名问题.
这对所有值都不安全.包含a的值Cell可以调用内部可变性并最终违反内部约束,这些约束在通过未传播该更改的值进行访问时会导致不安全行为.
问题是我可以对T可以使其安全的通用设施施加什么约束?据我所知,我只需要UnsafeCell通过指针除外.
T: Copy?T: Copy 看起来像是一个不错的解决方案,但有两个主要缺点:
"没有绝对的根本原因,为什么[ UnsafeCell]没有实现Copy" - 亚历克斯克里奇顿.这个Copy要求似乎是巧合,而不是保证.
Copy禁止太多; Vec不是,Copy但不需要被禁止.
T: SyncSync 因为,接近正确的想法
不属于类型
Sync是那些具有"室内易变性"在非线程安全的方式,比如Cell和RefCell中std::cell.
但是,有几个类型,如原子能,有内部的可变性这是线程安全的.
您可以UnsafeCell使用自动特征强制执行约束.这些是默认定义的,但可以选择使用特定类型的特殊语法 - 您只想选择退出UnsafeCell.
这些以前称为Opt-In内置特征(OIBIT),但由于它们既不是选择性的也不是内置的,因此被重命名,并且实际上是可以在普通用户代码中定义的选择性特征.
首先启用它,创建特征并默认实现.这使用了一些神奇的语法.
#![feature(optin_builtin_traits)]
pub unsafe trait CopyRef {}
unsafe impl CopyRef for .. {}
Run Code Online (Sandbox Code Playgroud)
然后你选择退出UnsafeCell.
// Opt out of interior mutability
impl<T: ?Sized> !CopyRef for UnsafeCell<T> {}
Run Code Online (Sandbox Code Playgroud)
然后,您将需要重新启用UnsafeCell后面的指针和PhantomData.
use std::marker::PhantomData;
use std::cell::UnsafeCell;
// Opt in for indirect interior mutability
unsafe impl<'a, T: ?Sized> CopyRef for *const T {}
unsafe impl<'a, T: ?Sized> CopyRef for *mut T {}
unsafe impl<'a, T: ?Sized> CopyRef for &'a T {}
unsafe impl<'a, T: ?Sized> CopyRef for &'a mut T {}
// Box is special and needs its own opt-in
unsafe impl<T: ?Sized> CopyRef for Box<T> {}
// And fake interior mutability
unsafe impl<T: ?Sized> CopyRef for PhantomData<T> {}
Run Code Online (Sandbox Code Playgroud)
瞧.您自己的用户定义选择退出Opt-In内置自动特征.