キー型の変種 - Rust By Example
Description: Rust by Example (RBE) is a collection of runnable examples that illustrate various Rust concepts and standard libraries.

## Keyboard shortcuts

Press `←` or `→` to navigate between chapters

Press `S` or `/` to search in the book

Press `?` to show this help

Press `Esc` to hide this help

# キー型の変種

`Eq`と`Hash`トレイトを実装している型ならば、なんでも`HashMap`のキーになることができます。例えば以下です。

- `bool` （キーになりうる値が2つしかないので実用的ではないですが…）
- `int`、`uint`、あるいは他の整数型
- `String`と`&str`（Tips：`String`をキーにしたハッシュマップを作製した場合、`.get()`メソッドの引数に`&str`を与えて値を取得することができます。）

`f32`と`f64`は`Hash`を実装して いない ことに注意しましょう。おそらくこれは浮動小数点演算時に誤差が発生するため、キーとして使用すると、恐ろしいほどエラーの元となるためです。

集合型は、その要素となっている全ての型が`Eq`を、あるいは`Hash`を実装している場合、必ず同じトレイトを実装しています。例えば、`Vec<T>`は`T`が`Hash`を実装している場合、`Hash`を実装します。

独自の型に`Eq`あるいは`Hash`を実装するのは簡単です。以下の一行で済みます。`#[derive(PartialEq, Eq, Hash)]`

後はコンパイラがよしなにしてくれます。これらのトレイトの詳細をコントロールしたい場合、`Eq`や`Hash`を自分で実装することもできます。この文書では`Hash`トレイトを実装する方法の詳細については触れません。

`struct`を`HashMap`で扱う際の例として、とてもシンプルなユーザーログインシステムを作成してみましょう。

    use std::collections::HashMap;

    // Eqトレイトを使用する時は、PartialEqをderiveする必要があります。
    #[derive(PartialEq, Eq, Hash)]
    struct Account<'a>{
        username: &'a str,
        password: &'a str,
    }

    struct AccountInfo<'a>{
        name: &'a str,
        email: &'a str,
    }

    type Accounts<'a> = HashMap<Account<'a>, AccountInfo<'a>>;

    fn try_logon<'a>(accounts: &Accounts<'a>,
            username: &'a str, password: &'a str){
        println!("Username: {}", username);
        println!("Password: {}", password);
        println!("Attempting logon...");

        let logon = Account {
            username,
            password,
        };

        match accounts.get(&logon) {
            Some(account_info) => {
                println!("Successful logon!");
                println!("Name: {}", account_info.name);
                println!("Email: {}", account_info.email);
            },
            _ => println!("Login failed!"),
        }
    }

    fn main(){
        let mut accounts: Accounts = HashMap::new();

        let account = Account {
            username: "j.everyman",
            password: "password123",
        };

        let account_info = AccountInfo {
            name: "John Everyman",
            email: "j.everyman@email.com",
        };

        accounts.insert(account, account_info);

        try_logon(&accounts, "j.everyman", "psasword123");

        try_logon(&accounts, "j.everyman", "password123");
    }