在没有不安全块的情况下不可能解决的棘手问题是在结构中保存对此结构的其他属性所拥有的东西的引用。
但是,对于不安全的块,这很容易,可以执行以下操作:
struct Foo {
bar: &'static str,
foo: String
}
impl Foo {
pub fn new(s: String) -> Foo {
Foo {
bar: unsafe { ::std::mem::transmute(&s[..]) },
foo: s
}
}
}
问题是:如果之前定义的结构体
Foo
没有任何方法给予 &mut
访问它的权限(因此该结构体在创建后永远不会被修改),知道 String
的数据是堆分配的,是这段代码实际上安全(根据 Rust 的“安全”含义)?如果不是的话,什么情况下可能会出现问题?
&mut
访问并不那么重要。重要的是 String
永远不会改变(至少 &'static str
不会改变),其他数据可以改变我们所关心的一切。此外,如果 &mut
允许第三方代码更改字符串,那么他们也可以通过继承的可变性在没有指针的情况下更改它:
let x = Foo::new(string);
let mut x = x;
x.foo = other_string;
println!("{}", x.bar); //
因此,至少您必须保持属性私有并审核同一模块中的所有代码(而不仅仅是
impl Foo
!)。但还有另一个问题:
如果您曾经分发过&'static str
,那么是的,这是不安全的:
let x = Foo::new(string);
let s: &'static str = obtain_str(x);
drop(x);
println!("{}", s); // use after free
因此,您可以通过这种自我参考安全地做的事情是非常有限的。第二个问题可以,也许,通过适当使用生命周期来避免,但这进入了我不愿意在没有详细的半正式论证的情况下接受安全性的领域。
对于我想象的用例,硬着头皮远离
unsafe
可能更容易。