2017-02-25 15 views
3

は、私たちがこのようになります列挙型があるとします。Rustの列挙型フィールドを変更する簡単な方法はありますか?

enum MyEnum { 
    Field1, 
    Field2 {x: f64, y: f64}, 
    /* Maybe some other fields */ 
    MyString(String), 
} 

は今、私はサブタイプMyStringのこの列挙のインスタンスを作成し、いくつかのアクションの後、私はそれを変異させたいです。例えば:私たちはmy_enumのみMyStringすることができ、コンテキストから正確に知っているとき

fn main() { 
    let mut my_enum = MyEnum::MyString("Hello, world".to_string()); 
    /* Some actions */ 
    // Mutating the string 
    match my_enum { 
     MyEnum::MyString(ref mut content) => { 
      content.push('!'); 
     }, 
     _ => {} 
    } 
    // Printing the string 
    match my_enum { 
     MyEnum::MyString(content) => { 
      println!("{}", content); 
     }, 
     _ => {} 
    } 
} 

しかし、このように一致することはかなり面倒です。私は何かを行うことができます

[email protected] += 1.0; 

[email protected]('!'); 
println!("{}", [email protected]); 

と仮定し、もし、my_enumは、サブタイプField2であり、その後、xを変異させる:私はむしろ、この(ない正しい錆構文)のようなものを書きますこのような?私は上記の試合から_ => {}を削除する場合ので、私は強く、答えは「ノー」であると仮定し、型チェッカーは、非網羅的パターンマッチングに文句を開始:my_enumはなく、何もないことを推測できるものの

patterns `Field1` and `Field2` not covered 

MyString。 "推論"とは、コンパイラがタイプMyEnumのすべての変数を正確に含めることができる値のサブタイプを追跡できることを意味します。

このコードは便利な場所にありますが、他の方法で書き直すことができます。しかし、私はコンパイラがよりスマートになり、この文脈ではMyEnum::MyStringというパターンが網羅的であることを少なくとも理解すると思う。上記の質問に対する回答が本当に「いいえ」であると思われる場合は、この問題がRustの開発者(RFCSのリンクかもしれません)の間で議論されていて、機能要求を行う価値があるのであれば興味があります。

+0

'MyEnum ::のMyString(REF MUTの内容を)聞かせている場合= my_enum {content.push( '!'); } ' – ildjarn

答えて

4

Rust 1.15.1から、コンパイラは特定の変数がある実行ポイントでenumの特定の変種にしかなり得ないことを認識しません。そのため、常にmatchを網羅する必要があります。

しかし、一部のRust開発者have been consideringは、enumの各タイプが独自のタイプになるようにしています。enumのサブタイプです。

あなたのバリエーションは多くのデータフィールドを持っている、またはあなたがそれに接続されているメソッドを持っている場合、あなたはstructenumバリアントのフィールドをラップ考慮し、あなたは何のために列挙しなければならないのまで直接structは、完全に列挙型をバイパスすることを使用することができた場合理由。いくつかのフィールドだけを持ち、列挙型のメソッドを呼び出す必要がない場合は、冒頭で取得したフィールドごとに可変ポインタを保持して、このように徹底的にmatch

fn main() { 
    let mut my_enum = MyEnum::MyString("Hello, world".to_string()); 
    let content = 
     match my_enum { 
      MyEnum::MyString(ref mut content) => content, 
      _ => unreachable!(), 
     }; 

    /* Some actions */ 
    // Mutating the string 
    content.push('!'); 

    // Printing the string 
    println!("{}", content); 
} 
6

あなたは変数が特定の型を持つことが知られているコードのセクション全体を持っている場合は 、あなたが気に一つだけmatchの腕があるかどうあなただけmatch内部でそのコードを置く、または可能性があり、 if let

fn main() { 
    let mut my_enum = MyEnum::MyString("Hello, world".to_string()); 
    /* Some actions */ 
    if let MyEnum::MyString(ref mut content) = my_enum { 
     content.push('!'); 
     //... 
     println!("{}", content); 
    } 
} 

また、冗長なmatch(またはif let)の問題がある、あなたはそれが整然とさせるためのメソッドを記述することができます。

impl MyEnum { 
    fn push(&mut self, char c) { 
     if let MyEnum::MyString(ref mut content) = *self { 
      content.push(c); 
     } else { 
      unreachable!(); 
     } 
    } 

    // In practice print might be more generic, for example implement 
    // Display 
    fn print(&self) { 
     if let MyEnum::MyString(ref content) = *self { 
      println!("{}", content); 
     } 
    } 
} 

fn main() { 
    //... 
    my_enum.push('!'); 
    my_enum.print(); 
} 
関連する問題