所以我正在查看 impl foris_some()
forOption
,我注意到它在引擎盖下使用了match *self {}
......所以它在内部移动它。
我的问题是,如果它被移动了,我怎么能做这样的事情?https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=f094da12290b77bad526674467e51043
fn main() {
let x = Option::Some(3);
x.is_some();
x.is_some();
}
我的期望是我应该只能调用is_some()
一次,下次我调用它时,我应该会收到某种错误,说它已被移动......但是不,这一切都编译得很好。
我误解了什么?
match *self { ... }
中的*self
不会移动(或复制(self
指向的内容。来自"The Rust Reference"(强调我的(,
match
的行为会有所不同,具体取决于仔细检查表达式是位置表达式还是值表达式。如果仔细表达式是值表达式,则首先将其计算到临时位置,...当 scrutinee 表达式是 place 表达式时,匹配项不会分配临时位置;但是,按值绑定可能会从内存位置复制或移动。
*self
是一个地方表达式。来自"The Rust Reference"(强调我的(,
分为两大类:位置表达式和值表达式。
位置表达式是表示内存位置的表达式。这些表达式是引用局部变量、静态变量、取消引用 (
*expr
(、数组索引表达式 (expr[expr]
(、字段引用 (expr.f
( 和括号中的 place 表达式的路径。所有其他表达式都是值表达式。值表达式是表示实际值的表达式。
您可能还有兴趣知道match
体内的Some(_) => true
臂不会束缚任何东西。来自"锈参考",
与标识符模式不同,它不会复制、移动或借用它匹配的值。
其中"it"表示通配符模式(_
(。
(有关更官方和引用的答案,请参阅@dkim的答案(
如果函数的签名通过引用接受,则它不会获得值的所有权。Option.is_some(( 实际上采取 &self 而不是自我。
有趣的部分是如何允许在函数中使用*self
,该函数在Self: Copy
不受限制时接收&self
。
为了测试这一点,让我们创建一个包含类似内容的最小示例:https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=d7b137b74b5cd8f8bb57398ae01bf4e3
#[derive(Debug)]
pub enum A {
X(String),
Y(i32),
}
pub fn f(a: &A) {
match *a {
A::X(_) => {
// dbg!(s);
}
A::Y(_i) => {
// dbg!(i);
}
};
}
这编译得很好。但是,让我们将A::X(_)
模式更改为A::X(_s)
:https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=93030e5c3f84532532c5db966c798bd6
#[derive(Debug)]
pub enum A {
X(String),
Y(i32),
}
pub fn f(a: &A) {
match *a {
A::X(_s) => {
// dbg!(s);
}
A::Y(_i) => {
// dbg!(i);
}
};
}
这无法编译:
error[E0507]: cannot move out of `a.0` which is behind a shared reference
--> src/lib.rs:7:11
|
7 | match *a {
| ^^ help: consider borrowing here: `&*a`
8 | A::X(_s) => {
| --
| |
| data moved here
| move occurs because `_s` has type `std::string::String`, which does not implement the `Copy` trait
因此,取消引用非复制枚举似乎是完全可以的,只要它不用于移动内部非复制值。_
很好,因为它保证永远不会使用基础值,而_s
不会编译,因为它只是一个普通的 allow(未使用(变量。
这也是有道理的,因为它允许相同的匹配臂同时适用于复制和非复制类型,只要没有使用违反所有权规则