Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

modifying a field while pattern matching on it

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 => ()
}
like image 443
flying sheep Avatar asked Apr 29 '13 23:04

flying sheep


People also ask

What is pattern matching explain with example?

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.

When to use 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.

Which allows us to perform matching on data or an object?

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.

What is pattern matching in Linux?

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.


1 Answers

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

like image 132
pnkfelix Avatar answered Nov 11 '22 20:11

pnkfelix