6

私は今日初めて Rust を試しました (XML トークナイザーを作成しました) が、もちろんすべてを理解しているわけではありません。

列挙値を取ることができるフィールドを持つ構造体があります:

enum State { Outside, InATag(~str) }
struct Tokenizer { state: State }

ではimpl Tokenizer、現在の状態で一致させ、場合によっては変更したいのですが、これは常にuse of moved valueエラーになります。

H は状態フィールドにアクセスおよび/または宣言して、それに基づいて一致させ、一致ブランチ内でその値を変更できるようにしますか?


混乱させて申し訳ありません。状態の文字列フィールドではなく、トークナイザーの状態フィールドを変更するつもりでした!

match self.state {
    InATag(name) => self.state = Outside,
    Outside => ()
}
4

2 に答える 2

5

より具体的な例がなければ、これで問題が解決するかどうかを判断するのは困難ですが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));
}

この種のコードを実行する場合、エイリアシングが原因で誤ってボロー チェック違反が発生しやすいことに注意してください。たとえば、上記の 2 番目の例の比較的小さな変更はコンパイルされません。

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

于 2013-04-30T12:24:04.623 に答える
2

さて、質問の明確な変形で、ここに私の修正された答えがあります:

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}
% 
于 2013-05-01T12:02:12.187 に答える