Pointers 在对字段进行模式匹配时修改该字段
今天,我第一次尝试了Rust(编写XML标记器),但自然不了解所有内容: 我有一个带字段的结构,可以接受枚举值:Pointers 在对字段进行模式匹配时修改该字段,pointers,pattern-matching,rust,Pointers,Pattern Matching,Rust,今天,我第一次尝试了Rust(编写XML标记器),但自然不了解所有内容: 我有一个带字段的结构,可以接受枚举值: enum State { Outside, InATag(~str) } struct Tokenizer { state: State } 在impl标记器中,我希望匹配当前状态,并在某些情况下对其进行更改,但是这总是会导致使用移动值错误 H访问和/或声明状态字段,以便在匹配分支中匹配并更改其值 很抱歉造成混淆,我的意思是更改标记器的状态字段,而不是状态的字符串字段 match
enum State { Outside, InATag(~str) }
struct Tokenizer { state: State }
在impl标记器
中,我希望匹配当前状态,并在某些情况下对其进行更改,但是这总是会导致使用移动值
错误
H访问和/或声明状态字段,以便在匹配分支中匹配并更改其值
很抱歉造成混淆,我的意思是更改标记器的状态字段,而不是状态的字符串字段
match self.state {
InATag(name) => self.state = Outside,
Outside => ()
}
如果没有更具体的示例,很难判断这是否能解决您的问题,但是您可以在匹配模式中使用
ref
来引用匹配的子结构,并且可以使用ref mut
使该引用可变
因此,在您的示例中:
enum State { Outside, InATag(~str) }
struct Tokenizer { state: State }
fn main() {
let mut t = Tokenizer { state: InATag(~"foo") };
match t.state {
InATag(ref mut _s) => { *_s = ~"bar"; }
Outside => { /* impossible */ }
}
io::println(fmt!("Hello World: %?", t));
}
或者,如果需要匹配标记器状态的其他部分,也可以这样做:
fn main() {
let mut t = Tokenizer { state: InATag(~"foo") };
match t {
Tokenizer { state: InATag(ref mut _s) } => { *_s = ~"bar"; }
Tokenizer { state: Outside } => { /* impossible */ }
}
io::println(fmt!("Hello World: %?", t));
}
请注意,在执行此类代码时,由于别名,很容易在不经意间遇到借用检查冲突。例如,下面是对上面第二个示例的一个相对较小的更改,它不会编译:
导致来自rustc的以下消息:
/tmp/m.rs:7:35: 7:46 error: illegal borrow: creating mutable alias to enum content
/tmp/m.rs:7 &Tokenizer { state: InATag(ref mut _s) } => { *_s = ~"bar"; }
^~~~~~~~~~~
error: aborting due to previous error
因为您不想在为
t
的内部创建可变别名的同时,借用未完成的&t
好的,下面是我的修订答案:
enum State { Outside, InATag(~str) }
struct Tokenizer { state: State }
impl Tokenizer {
fn toggle(&mut self) {
match self {
&Tokenizer { state: InATag(*) } => { self.state = Outside }
&Tokenizer { state: Outside } => { self.state = InATag(~"baz") }
}
}
}
fn main() {
let mut t1 = Tokenizer { state: InATag(~"foo") };
match t1 {
Tokenizer { state: InATag(*) } => { t1.state = Outside }
Tokenizer { state: Outside } => { /* impossible */ }
}
io::println(fmt!("Hello t1: %?", t1));
let mut t2 = Tokenizer { state: InATag(~"bar") };
t2.toggle();
io::println(fmt!("World t2: %?", t2));
}
我承认,我实际上并不期望它像上面那样简单,而且我可以很容易地相信,对上面代码的微小更改可能会导致它开始无法借用支票。但是如果提问者没有一个更具体的例子,就很难判断上面的代码是否适合他的目的
哦,这是我编译和运行代码时的输出:
% rustc /tmp/m.rs
warning: no debug symbols in executable (-arch x86_64)
% /tmp/m
Hello t1: {state: Outside}
World t2: {state: Outside}
%
你使用的是什么版本的Rust?Rust语言变化很快,语法和语义还没有固定下来。特别是,我非常肯定,
match
的行为最近发生了变化(或者将发生变化,可能在0.7中)。这个答案当然有助于我理解更多关于生锈的内容,但我似乎表达得很糟糕:我想切换状态,而不是修改其值。抱歉搞混了!我会相应地更新我的问题。太棒了,谢谢!因此,在方法中需要一个指向self的可变指针,这很有意义!
% rustc /tmp/m.rs
warning: no debug symbols in executable (-arch x86_64)
% /tmp/m
Hello t1: {state: Outside}
World t2: {state: Outside}
%