提问人:Incömplete 提问时间:8/16/2023 最后编辑:user3840170Incömplete 更新时间:8/17/2023 访问量:88
如何使“复制”值在使用后无法访问?
How do I make a `Copy` value inaccessible after use?
问:
struct S {
foo: i32,
// ... other fields
}
fn f(s: S) {
// transform foo
let new_foo = biz_logic(s.foo);
// from now on, the code should read `new_foo` whenever it needs `s.foo`,
// how do I "drop" the `s.foo` to prevent misuse?
// obviously `drop(s.foo)` won't work since it is `Copy`
// is there any idiom to do this?
drop(s.foo);
// OK
let _ = ... new_foo ...;
// Not OK
let _ = ... s.foo ...;
}
有没有鲜为人知的 rust 功能可以让你在 Copy 上获得与 drop() 相同的结果?
答:
0赞
Filipe Rodrigues
8/16/2023
#1
一种选择是使用可变阴影。但是,你不能 shadow ,所以除非你愿意用 替换它的值并继续使用 ,否则你可以绑定到一个局部变量,然后用 的结果 shadow 它:s.foo
new_foo
s.foo
s.foo
foo
biz_logic
fn f(s: S) {
let foo = s.foo;
// Use `foo` for whatever
// ...
// Shadow `foo` so the old value can't be accessed anymore.
let foo = biz_logic(foo);
// Usages of `foo` will always access the new `foo`.
}
评论
0赞
user3840170
8/17/2023
但仍然可以访问。s.foo
1赞
Sam
8/17/2023
#2
如果您对 的其余部分不感兴趣,那么解构和删除将起作用:s
fn f(s: S) {
let S { foo, .. } = s;
drop(s);
// okay
println!("{foo}");
// not okay
// println!("{}", s.foo);
}
不幸的是,如果你想得到其余部分(假设其中一些不是),这种方法是行不通的,因为解构分配将导致部分移动,这将使可访问且无法手动删除。s
Copy
s.foo
s
更好的选择可能是在函数签名和阴影中解构:
fn f(S { foo, .. }: S) {
let foo = biz_logic(foo);
// foo is now result of biz_logic and foo from S is unreachable
}
评论
0赞
Filipe Rodrigues
8/17/2023
不幸的是,如果有一个 impl,那么你就无法解构或移出它。(尽管有计划允许这样做)。S
Drop
ManuallyDrop
3赞
Silvio Mayolo
8/17/2023
#3
如果要更改现有类型的属性,则需要查找 newtype 模式。我们可以制作一个 newtype 包装器,其行为类似于但没有实现。i32
i32
Copy
struct MyI32Resource(pub i32);
那么 can 的类型是 ,它遵循 Rust 的默认移动语义,因为我们还没有为它实现。您可以实现任何需要委托给内部字段的类似特征的特征。同样,您也可以将新资源类型取消引用为 .s.foo
MyI32Resource
Copy
i32
MyI32Resource
impl Deref
i32
此方法应仅用于在移动后使用现有值在语义上不合适的情况。也就是说,你真正认为 是某种真正无法复制的资源(Unix 风格的文件描述符就是一个很好的例子;它们只是整数,但从语义上讲,我们希望对它们施加类似资源的约束)。i32
如果你只是担心有人在特定函数中重复使用相同的名称,那么这种方法可能有点矫枉过正,而 Filipe 的方法在这方面更干净。
评论
s.foo
std::mem::replace(&mut s.foo, new_foo);
s.foo
Copy
i32
Copy
数据应该代表纯粹的信息,无论其来源如何,都可以不加选择地复制和使用。如果您想要一个值只能存在于一个地方的类型,请使用不是 的数据类型,例如使用 newtype 习惯用语:<doc.rust-lang.org/rust-by-example/generics/new_types.html>。Copy