我试图在
Copy
值类型(用于缓存目的)。
问题是,据我所知,没有一种类型可用于内部可变性(例如。
UnsafeCell
以及相关类型、原子类型)允许
复制
特质
这是稳定的Rust btw
。
我的问题是:使用安全性如何
std::ptr::write_volatile
和
std::ptr::read_volatile
在这种情况下实现内部可变性?
具体来说,我有这样的代码,我想知道其中是否有任何gotcha或未定义的行为:
use std::fmt::{Debug, Display, Formatter};
#[derive(Copy, Clone)]
pub struct CopyCell<T: Copy> {
value: T,
}
impl<T: Copy> CopyCell<T> {
pub fn new(value: T) -> Self {
Self { value }
}
pub fn get(&self) -> T {
unsafe { std::ptr::read_volatile(&self.value) }
}
pub fn set(&self, value: T) {
let ptr = &self.value as *const T;
let ptr = ptr as *mut T;
unsafe { std::ptr::write_volatile(ptr, value) }
}
}
impl<T: Default + Copy> Default for CopyCell<T> {
fn default() -> Self {
CopyCell { value: T::default() }
}
}
impl<T: Display + Copy> Display for CopyCell<T> {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
let value = self.get();
write!(f, "{value}")
}
}
impl<T: Debug + Copy> Debug for CopyCell<T> {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
let value = self.get();
write!(f, "{value:?}")
}
}
我的目标是使用它在值类型中实现本地缓存(例如,一种内存化)。我特别想要
复制
语义(即
Clone
)因为他们有更好的人体工程学来实现我想要实现的目标。
以下是用法示例:
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn simple_test() {
let a = CopyCell::default();
let b = CopyCell::new(42);
assert_eq!(a.get(), 0);
assert_eq!(b.get(), 42);
a.set(123);
b.set(b.get() * 10);
assert_eq!(a.get(), 123);
assert_eq!(b.get(), 420);
let a1 = a;
let b1 = b;
a.set(0);
b.set(0);
assert_eq!(a1.get(), 123);
assert_eq!(b1.get(), 420);
}
#[test]
fn cached_compute() {
let a = CachedCompute::new(10);
assert_eq!(a.compute(), 100);
assert_eq!(a.compute(), 100);
let b = a;
assert_eq!(b.compute(), 100);
}
#[derive(Copy, Clone)]
pub struct CachedCompute {
source: i32,
result: CopyCell<Option<i32>>,
}
impl CachedCompute {
pub fn new(source: i32) -> Self {
Self {
source,
result: Default::default(),
}
}
pub fn compute(&self) -> i32 {
if let Some(value) = self.result.get() {
value
} else {
let result = self.source * self.source; // assume this is expensive
self.result.set(Some(result));
result
}
}
}
}
上面的代码乍一看是有效的。但我想知道这种方法是否存在任何表面上不明显的潜在问题。
我对Rust的内存模型、编译器优化、机器代码级语义等没有足够的了解,这可能会在这种情况下造成问题。
即使这种方法适用于当前的平台,我也想知道我是否会在未来遇到关于未定义行为的潜在问题。