Perl日記

日々の知ったことのメモなどです。Perlは最近やってないです。

Rust で HashSet の要素や HashMap のキーに使う型は Eq と Hash トレイトを実装している必要がある

HashSet in std::collections - Rust
HashMap in std::collections - Rust



自前の構造体を HashSet の要素にしたり、HashMap のキーに使用するとコンパイルエラーになる。

use std::collections::HashSet;
fn main() {
    {
        struct MyFoo {
            x: i32,
        }
        let mut hs: HashSet<MyFoo> = HashSet::new();
        hs.insert(MyFoo { x: 123 });
        hs.insert(MyFoo { x: 234 });
        for e in hs.iter() {
            println!("{}", e.x);
        }
    }
}
error[E0599]: the method `insert` exists for struct `HashSet<MyFoo>`, but its trait 
bounds were not satisfied
 --> examples\hm_error.rs:8:12
  |
4 |         struct MyFoo {
  |         ------------
  |         |
  |         doesn't satisfy `MyFoo: Eq`
  |         doesn't satisfy `MyFoo: Hash`
...
8 |         hs.insert(MyFoo { x: 123 });
  |            ^^^^^^ method cannot be called on `HashSet<MyFoo>` due to unsatisfied trait bounds
  |
  = note: the following trait bounds were not satisfied:
          `MyFoo: Eq`
          `MyFoo: Hash`
help: consider annotating `MyFoo` with `#[derive(Eq, Hash)]`
  |
4 |         #[derive(Eq, Hash)]
  |

error[E0599]: the method `insert` exists for struct `HashSet<MyFoo>`, but its trait 
bounds were not satisfied
 --> examples\hm_error.rs:9:12
  |
4 |         struct MyFoo {
  |         ------------
  |         |
  |         doesn't satisfy `MyFoo: Eq`
  |         doesn't satisfy `MyFoo: Hash`
...
9 |         hs.insert(MyFoo { x: 234 });
  |            ^^^^^^ method cannot be called on `HashSet<MyFoo>` due to unsatisfied trait bounds
  |
  = note: the following trait bounds were not satisfied:
          `MyFoo: Eq`
          `MyFoo: Hash`
help: consider annotating `MyFoo` with `#[derive(Eq, Hash)]`
  |
4 |         #[derive(Eq, Hash)]
  |

For more information about this error, try `rustc --explain E0599`.

derive で Hash と Eq をつければ良いようだ。しかしその2つだとインスタンス同士の比較ができなくて、PartialEq もつけるといいよ!、とメッセージが出るので、そのようにするとうまくいった。

        #[derive(Hash, Eq, PartialEq)]
        struct MyFoo {
            x: i32,
        }

同様に、HashMap のキーのときも同じ対応でいけた。

        #[derive(Hash, Eq, PartialEq)]
        struct MyFoo {
            x: i32,
        }
        let mut hm: HashMap<MyFoo, &str> = HashMap::new();
        hm.insert(MyFoo { x: 123 }, "123");
        hm.insert(MyFoo { x: 234 }, "234");
        for (k, v) in hm.iter() {
            println!("{}, {}", k.x, v);
        }