在 Rust 中设计一个具有可变 getter 和不可变 getter 的特征,并默认实现不可变 getter

问题描述 投票:0回答:1

我想为

self
的某个领域设计一个具有可变和不可变吸气剂的特征。 但是,我希望 trait 的实现者只需要实现一个方法,通常是可变的 getter。

我找到了这个解决方案(playground):

pub trait MyTrait<T> {
    fn inside_mut(&mut self) -> &mut T; 
    
    fn inside_ref(&self) -> &T {
        let ptr = self as *const Self as *mut Self;
        &* unsafe { &mut *ptr }.inside_mut()
    }
}

pub struct Data(String);
impl MyTrait<String> for Data {
    fn inside_mut(&mut self) -> &mut String { &mut self.0 }
}

fn main() {
    let mut data = Data(format!("Foo"));
    let x: &String = data.inside_ref();
    let y: &String = data.inside_ref();
    println!("x -> {x}");
    println!("y -> {y}");
    *data.inside_mut() = format!("Bar");
    println!("data.0 -> {}", data.0);
}

结果:

Standard Error

   Compiling playground v0.0.1 (/playground)
    Finished release [optimized] target(s) in 0.93s
     Running `target/release/playground`

Standard Output

x -> Foo
y -> Foo
data.0 -> Bar

我的问题:这种方法合理吗?

rust immutability traits mutable unsafe
1个回答
2
投票

不,这不是声音。

用户可以在他的

self
实现中修改
inside_mut
,这也会修改
inside_ref
中的结构。

像这样:

pub trait MyTrait<T> {
    fn inside_mut(&mut self) -> &mut T;

    fn inside_ref(&self) -> &T {
        let ptr = self as *const Self as *mut Self;
        &*unsafe { (&mut *ptr).inside_mut() }
    }
}

#[derive(Debug)]
struct MyStruct {
    value: i32,
}

impl MyTrait<i32> for MyStruct {
    fn inside_mut(&mut self) -> &mut i32 {
        self.value += 1;
        &mut self.value
    }
}

fn main() {
    // Important: this is not `mut`!!!
    let x = MyStruct { value: 42 };

    println!("{:?}", x);
    x.inside_ref();
    println!("{:?}", x);
}
MyStruct { value: 42 }
MyStruct { value: 43 }

这意味着这个实现是不健全的

行为被认为是未定义的

  • 改变不可变数据。
    const
    项目中的所有数据都是不可变的。此外,通过共享引用访问的所有数据或不可变绑定拥有的数据都是不可变的,除非该数据包含在
    UnsafeCell<U>
    .
© www.soinside.com 2019 - 2024. All rights reserved.