rust - 这种使用不安全的琐碎安全吗?
问题描述
我遇到了一个 Rust 借用检查器错误,我认为这是对非词法生命周期当前实现的限制。我要编写的代码如下所示:
struct Thing {
value: i32
}
impl Thing {
fn value(&self) -> &i32 {
&self.value
}
fn increment(&mut self) {
self.value += 1;
}
}
/// Increments the value of `thing` if it is odd, and returns a reference to the value.
fn increment_if_odd(thing: &mut Thing) -> &i32 {
let ref_to_value = thing.value();
if (*ref_to_value % 2) == 0 {
return ref_to_value;
}
thing.increment(); // fails to compile because the immutable borrow `ref_to_value` is still alive
thing.value()
}
锈游乐场。
第一个问题:我是否认为这段代码是 100% 安全的,而借用检查器过于保守?返回的分支ref_to_value
不会发生变异thing
,因此可以保证引用是有效的,而另一个分支根本不使用ref_to_value
。(我知道如果我用它替换return ref_to_value;
它return thing.value();
会编译,但在我的实际代码中,该value
方法很昂贵。)
看来我可以通过指针“清洗”引用来解决这个问题:
if (*ref_to_value % 2) == 0 {
return unsafe {
&*(ref_to_value as *const i32)
}
}
第二个问题:这是微不足道的安全吗?我以前从未使用过 unsafe,所以我很紧张。
我想第三个问题:有没有办法用安全的 Rust 重写它?约束是value
应该只在非变异路径上调用一次。
解决方案
编译器不允许您的代码的原因是因为 ref_to_value 的生命周期必须至少与 increment_if_odd 的生命周期一样长才能返回。
如果您添加回省略的生命周期,则 ref_to_value 必须具有生命周期'a。我的理解是编译器不能改变引用的生命周期。编写安全 rust 来解决此问题的一种方法是使 ref_to_value 可变,并修改 Thing::increment。
您的不安全代码所做的是允许编译器为 ref_to_value 提供更短的生命周期,以及通过强制转换指针生命周期'a 创建的新引用。我认为你的不安全代码是“安全的”,因为没有任何 rust 的借用规则被破坏,而且我们知道新的引用不会比数据更有效。
struct Thing {
value: i32
}
impl Thing {
fn value(&self) -> &i32 {
&self.value
}
fn mut_value(&mut self) -> &mut i32{
&mut self.value
}
fn increment(val: &mut i32) {
*val += 1;
}
}
/// Increments the value of `thing` if it is odd, and returns a reference to the value.
fn increment_if_odd<'a>(thing: &'a mut Thing) -> &'a i32 {
let ref_to_value : &'a mut i32 = thing.mut_value();
if (*ref_to_value % 2) != 0 {
Thing::increment(ref_to_value);
}
ref_to_value
}
推荐阅读
- javascript - 使用 jquery ajax、.net mvc 进行无限滚动
- java - 无法从静态上下文引用 Generis 方法出错
- angularjs - 力矩未定义角力矩选择器
- python - DjangOAuthToolkit - 如何为视图设置不同的读/写范围?
- cmake - CMake 3.11中带尖括号的美元是什么意思
- php - 如何在 Wordpress 中使用 AJAX 基于多个过滤器选择从数据库中获取数据
- sql-server - MSDTC 错误 - 调用 RpcMgmtInqServerPrincName 失败。合作伙伴不支持安全呼叫
- python-3.x - 检查表金字塔-SQLalchemy 中是否存在记录?
- informatica-powercenter - 关于唯一序列的 Informatica 场景
- java - 使用 Citrus Admin UI 创建项目时出错