I tried my hands at Rust for the first time today (writing a XML tokenizer), and naturally don’t understand everything:
I have a struct with field that can take an enum value:
enum State { Outside, InATag(~str) }
struct Tokenizer { state: State }
In a impl Tokenizer
, I want to match on the current state, and change it in some cases, however this always gives a use of moved value
error.
H to access and/or declare the state field so that I can match on it and change its value inside a match branch?
Sorry for the confusion, I meant to change the Tokenizer’s state field, not the state’s String field!
match self.state {
InATag(name) => self.state = Outside,
Outside => ()
}
Pattern matching is the process of checking whether a specific sequence of characters/tokens/data exists among the given data. Regular programming languages make use of regular expressions (regex) for pattern matching.
You can use pattern matching to test the shape and values of the data instead of transforming it into a set of objects.
C# pattern matching is a feature that allows us to perform matching on data or any object. We can perform pattern matching using the is expression and switch statement. is expression is used to check, whether an object is compatible with given type or not. In the following example, we are implementing is expression.
3.5. 8.1 Pattern Matching. Any character that appears in a pattern, other than the special pattern characters described below, matches itself. The NUL character may not occur in a pattern. A backslash escapes the following character; the escaping backslash is discarded when matching.
Without a more concrete example, it is hard to tell whether this would solve your problem, but you can use ref
within a match pattern to make a reference to the matched substructure, and you can use ref mut
to make that reference mutable.
So, in your example:
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));
}
or if you need to match other parts of the Tokenizer state, this works too:
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));
}
Note that when doing this sort of code, it can be pretty easy to inadvertently run into borrow-check violations due to aliasing. For example, here is a relatively small change to the second example above that won't compile:
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));
}
causes the following message from 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
because you do not want an outstanding borrow &t
while you are also creating mutable aliases to the internals of t
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With