如何访问匹配表达式中绑定到变量的值的字段?
How to access fields of a value bound to a variable in a match expression?
我的代码类似于:
use std::string::{String};
use std::vec::{Vec};
enum State {
A {
n: usize,
lines: Vec<String>,
},
B {
n: usize,
}
}
fn main() {
use State::*;
let lines = vec!["a", "b", "GO", "c", "GO", "d"];
let mut state = B { n: 0 };
for line in &lines {
state = match state {
A { n, lines } => {
if line == &"GO" {
B { n: n + 1 }
} else {
let mut new_lines = Vec::from(lines);
new_lines.push(line.to_string());
A { n: n, lines: new_lines }
}
},
B { n } => {
A { n: n, lines: vec![line.to_string()] }
},
};
}
let final_n = match state {
A { n, .. } => n,
B { n } => n,
};
println!("final_n = {}", final_n);
}
Rust 游乐场 link:http://is.gd/0QTYaQ
(请注意,这是对实际代码的简化。有关完整背景,请参阅此问题的 first revision。)
我想避免创建 new_lines
向量,所以我尝试将 State::A
值绑定到一个变量并访问值的字段,如下所示:
s @ A { .. } => {
if line == &"GO" {
B { n: s.n + 1 }
} else {
s.lines.push(line.to_string());
s
}
},
然而,编译失败:
ParseState_enum_test.rs:23:28: 23:31 error: attempted access of field `n` on type `State`, but no field with that name was found
ParseState_enum_test.rs:23 B { n: s.n + 1 }
^~~
ParseState_enum_test.rs:19:5: 33:6 note: in this expansion of for loop expansion
ParseState_enum_test.rs:25:21: 25:28 error: attempted access of field `lines` on type `State`, but no field with that name was found
ParseState_enum_test.rs:25 s.lines.push(line.to_string());
^~~~~~~
ParseState_enum_test.rs:19:5: 33:6 note: in this expansion of for loop expansion
error: aborting due to 2 previous errors
如何访问绑定到变量的值的字段?
编辑: 我知道模式绑定中的 ref mut
,但我认为这对我来说不是一个好的解决方案。如果我使用 ref mut
,那么我需要创建向量的克隆,因为这段代码无法编译:
A { n, ref mut lines } => {
if line == &"GO" {
B { n: n + 1 }
} else {
lines.push(line.to_string());
A {
n: n,
lines: lines, // error: mismatched types
}
}
},
让我们看一下您的问题的更简单版本:
enum Foo {
Alpha { score: u8 },
Beta { lives_left: u8 },
}
fn main() {
let the_value = Foo::Alpha { score: 42 };
match the_value {
alpha_only @ Alpha => println!("Score is {}", alpha_only.score),
_ => println!("Dunno what to do!"),
}
}
问题是枚举变体不是独立类型。也就是说,不可能有一个Foo::Alpha
类型的变量;你只能让它成为 Foo
类型。您可以在错误消息中看到这一点:
attempted access of field score
on type Foo
, but no field with that name was found
当你使用@
绑定整个模式时,你只能知道你得到的是Foo
.
类型的东西
处理此问题的正常方法是使用 ref
:
绑定到项目的组件
match the_value {
Foo::Alpha { ref score } => println!("Score is {}", score),
_ => println!("Dunno what to do!"),
}
如果您需要更改值,请使用 ref mut
:
match the_value {
Foo::Alpha { ref mut score } => {
*score += 1;
println!("Score is {}", score)
},
_ => println!("Dunno what to do!"),
}
of如果能消费价值,就不需要ref
:
let the_value = Foo::Alpha { score: 42 };
let new_value = match the_value {
Foo::Alpha { score } => Foo::Alpha { score: score + 1 },
Foo::Beta { lives_left } => Foo::Alpha { score: lives_left * 2 },
};
以下似乎有效。它能解决问题吗?
let new_state = match state {
B {n} => A { n: n, lines: vec![line.to_string()] },
A {n, mut lines} => {
match *line {
"GO" => B { n: n + 1 },
_ => {
lines.push(line.to_string());
A{ n:n, lines: lines}
}
}
}
};
state = new_state
https://play.rust-lang.org/?gist=4fa712834999e45ccd4d&version=stable
我的代码类似于:
use std::string::{String};
use std::vec::{Vec};
enum State {
A {
n: usize,
lines: Vec<String>,
},
B {
n: usize,
}
}
fn main() {
use State::*;
let lines = vec!["a", "b", "GO", "c", "GO", "d"];
let mut state = B { n: 0 };
for line in &lines {
state = match state {
A { n, lines } => {
if line == &"GO" {
B { n: n + 1 }
} else {
let mut new_lines = Vec::from(lines);
new_lines.push(line.to_string());
A { n: n, lines: new_lines }
}
},
B { n } => {
A { n: n, lines: vec![line.to_string()] }
},
};
}
let final_n = match state {
A { n, .. } => n,
B { n } => n,
};
println!("final_n = {}", final_n);
}
Rust 游乐场 link:http://is.gd/0QTYaQ
(请注意,这是对实际代码的简化。有关完整背景,请参阅此问题的 first revision。)
我想避免创建 new_lines
向量,所以我尝试将 State::A
值绑定到一个变量并访问值的字段,如下所示:
s @ A { .. } => {
if line == &"GO" {
B { n: s.n + 1 }
} else {
s.lines.push(line.to_string());
s
}
},
然而,编译失败:
ParseState_enum_test.rs:23:28: 23:31 error: attempted access of field `n` on type `State`, but no field with that name was found ParseState_enum_test.rs:23 B { n: s.n + 1 } ^~~ ParseState_enum_test.rs:19:5: 33:6 note: in this expansion of for loop expansion ParseState_enum_test.rs:25:21: 25:28 error: attempted access of field `lines` on type `State`, but no field with that name was found ParseState_enum_test.rs:25 s.lines.push(line.to_string()); ^~~~~~~ ParseState_enum_test.rs:19:5: 33:6 note: in this expansion of for loop expansion error: aborting due to 2 previous errors
如何访问绑定到变量的值的字段?
编辑: 我知道模式绑定中的 ref mut
,但我认为这对我来说不是一个好的解决方案。如果我使用 ref mut
,那么我需要创建向量的克隆,因为这段代码无法编译:
A { n, ref mut lines } => {
if line == &"GO" {
B { n: n + 1 }
} else {
lines.push(line.to_string());
A {
n: n,
lines: lines, // error: mismatched types
}
}
},
让我们看一下您的问题的更简单版本:
enum Foo {
Alpha { score: u8 },
Beta { lives_left: u8 },
}
fn main() {
let the_value = Foo::Alpha { score: 42 };
match the_value {
alpha_only @ Alpha => println!("Score is {}", alpha_only.score),
_ => println!("Dunno what to do!"),
}
}
问题是枚举变体不是独立类型。也就是说,不可能有一个Foo::Alpha
类型的变量;你只能让它成为 Foo
类型。您可以在错误消息中看到这一点:
attempted access of field
score
on typeFoo
, but no field with that name was found
当你使用@
绑定整个模式时,你只能知道你得到的是Foo
.
处理此问题的正常方法是使用 ref
:
match the_value {
Foo::Alpha { ref score } => println!("Score is {}", score),
_ => println!("Dunno what to do!"),
}
如果您需要更改值,请使用 ref mut
:
match the_value {
Foo::Alpha { ref mut score } => {
*score += 1;
println!("Score is {}", score)
},
_ => println!("Dunno what to do!"),
}
of如果能消费价值,就不需要ref
:
let the_value = Foo::Alpha { score: 42 };
let new_value = match the_value {
Foo::Alpha { score } => Foo::Alpha { score: score + 1 },
Foo::Beta { lives_left } => Foo::Alpha { score: lives_left * 2 },
};
以下似乎有效。它能解决问题吗?
let new_state = match state {
B {n} => A { n: n, lines: vec![line.to_string()] },
A {n, mut lines} => {
match *line {
"GO" => B { n: n + 1 },
_ => {
lines.push(line.to_string());
A{ n:n, lines: lines}
}
}
}
};
state = new_state
https://play.rust-lang.org/?gist=4fa712834999e45ccd4d&version=stable