2013-04-29 2 views
3

я пытался мои руки в Руст в первый раз сегодня (написание XML Tokenizer), и, естественно, не все понимают:изменения поля во время сопоставления с образцом на нем

У меня есть поле с-структуру, которая может принимать значение перечисления:

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

в impl Tokenizer, я хочу, чтобы соответствовать по текущему состоянию, и изменить его в некоторых случаях, однако, это всегда дает ошибку use of moved value.

H для доступа и/или объявления поля состояния, чтобы я мог совместить его и изменить его значение внутри ветви соответствия?


Извините за недоразумение, я хотел изменить поле состояния токенизера, а не поле String состояния.

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

какая версия Rust вы используете? – barjak

+0

0,6, почему вы спрашиваете? –

+0

Язык Rust меняется быстро, синтаксис и семантика еще не исправлены. В частности, я уверен, что поведение 'match' изменилось в последнее время (или изменится, возможно, на 0,7). – barjak

ответ

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} 
% 
+0

потрясающе, спасибо! поэтому он нуждается в изменяемом указателе на себя в методе, что имеет большой смысл! –

4

Без более конкретного примера, то трудно сказать, будет ли это решить вашу проблему, но вы можете использовать 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)); 
} 

или, если вам нужно, чтобы соответствовать другим частям государства Tokenizer, это тоже работает:

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)); 
} 

Обратите внимание, что при выполнении такого рода кода, это может быть довольно легко непреднамеренно привести к нарушениям заимствования из-за сглаживания. Например, здесь относительно небольшое изменение во втором примере выше, что не будет компиляции:

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

+0

Этот ответ, безусловно, помогает мне понять больше о Rust, но, похоже, я плохо себя зарекомендовал: я хочу переключить состояние, а не изменять его значение. извините за путаницу! Я соответствующим образом обновляю свой вопрос. –