2016-05-30 6 views
9

私はHustMapsがRustでどのように動作するかを理解しようとしています。Rustで文字列とHashMapsを間接的に参照する

use std::collections::HashMap; 

fn main() { 
    let mut roman2number: HashMap<&'static str, i32> = HashMap::new(); 
    roman2number.insert("X", 10); 
    roman2number.insert("I", 1); 

    let roman_num = "XXI".to_string(); 
    let r0 = roman_num.chars().take(1).collect::<String>(); 
    let r1: &str = &r0.to_string(); 
    println!("{:?}", roman2number.get(r1)); // This works 

    // println!("{:?}", roman2number.get(&r0.to_string())); // This doesn't 
} 

私はコメントを外し、最後の行でコードをコンパイルしようとすると、私は次のエラー

error: the trait bound `&str: std::borrow::Borrow<std::string::String>` is not satisfied [E0277] 
println!("{:?}", roman2number.get(&r0.to_string())); 
              ^~~ 
note: in this expansion of format_args! 
note: in this expansion of print! (defined in <std macros>) 
note: in this expansion of println! (defined in <std macros>) 
help: run `rustc --explain E0277` to see a detailed explanation 

を取得docsの形質実装セクションがfn deref(&self) -> &str

としてデリファレンスを与えだから何がありますここで起こっている?

+0

ここで 'Borrow'特性を使うのは間違っていると思います(' HashMap :: get'を作成した人の誰か)。基本的には、ジェネリックバウンドには、キータイプがそのタイプとして借用可能である場合には、任意のタイプへの参照を 'get'に渡すことができます。実際には、キー型と互換性がある限り、どの型も 'get'に渡すことができます。しかし、私たちはこれを後方互換性を修正することはできません:( –

答えて

7

エラーは、型推論の間にコンパイラによってStringを超える汎用関数HashMap::getが選択されたことによって発生します。しかしstrを超えるHashMap::getが必要です。

だから、それを明示的にするために

println!("{:?}", roman2number.get::<str>(&r0.to_string())); 

println!("{:?}", roman2number.get(&r0.to_string())); 

を変更。これは、コンパイラが適切な関数を選択するのに役立ちます。

チェックアウトPlayground here

それは我々がターゲット・タイプを知っているときに強制 Deref<Target>のみ発生する可能性が私には見えます

ので、コンパイラが使用するHashMap::get推測しようとしているとき、それはタイプ&Stringとして&r0.to_string()決して&str見ています。 &'static strBorrow<String>を実装していません。この結果、型エラーが発生します。 HashMap::get::<str>と指定すると、この関数は&strを要求します。強制的に&Stringに強制的に適用して一致するのは&strです。

詳しくは、Deref coercionString Derefをご覧ください。 Q

fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V> where K: Borrow<Q>, Q: Hash + Eq 

最初の部分は、あなたが渡すオブジェクトの型である、次のように

+0

ありがとう、それは理にかなっていますが、Drefには2つの実装がありますか? – skanur

+0

['String'は' Deref 'のみを実装しています(https://doc.rust-lang.org/nightly/std/string/struct.String.html#deref)。この実装により、 '$ str'が期待される'&str'に '&String'を強制します。[' Deref'強制](https://doc.rust-lang.org/nightly/book/deref-coercions.html)を参照してください。 – WiSaGaN

1

get方法の定義が見えます。 Qには制約があります。 Q上の条件はQ

  • QBorrow形質を実装する

    1. キー型KニーズがHashEq特性を実装する必要があることです。

    これを実際のタイプに置き換えると、キータイプ&'static strBorrow<String>を実装する必要があります。 Borrowの定義によって、&'static str&Stringに変換可能である必要があることを意味します。しかし、私が読んだすべてのドキュメント/テキストでは、どこでも&Stringを使用すると、代わりに&strを使用してください。したがって、時々人生が少し楽になる場合でも、&str - >&Stringの変換を提供することはほとんど意味がありません。すべてのreference type is borrowable as a shorter lived reference type以来

    。)、あなたが渡すことができ&str&'static strは、他の答えが正しいBorrow<str>

  • +0

    ありがとう – skanur

    5

    を実装しているため&'static strは、キータイプは、ですが、私はあなたが不要なto_stringを持っていることを指摘したかったですではこれを

    let r0: String = roman_num.chars().take(1).collect(); 
    println!("{:?}", roman2number.get(&r0 as &str)); 
    

    :とasを使用して、&strに強制変換の代替方法(すでにcollectStringにEDをしました)場合、私はおそらくちょうどかのキーとしてcharを格納するためのマップを書き換えたい:

    use std::collections::HashMap; 
    
    fn main() { 
        let mut roman2number = HashMap::new(); 
        roman2number.insert('X', 10); 
        roman2number.insert('I', 1); 
    
        let roman_num = "XXI"; 
        for c in roman_num.chars() { 
         println!("{:?}", roman2number.get(&c)); 
        } 
    } 
    

    注意をマップの明示的な型を持っている必要はありません、それが推測されます。

    +0

    もう一つの同等な方法を追加するだけです: 'println!(" {{?} "、roman2number.get(r0.as_str()));'、new-ish [': :as_str'](https://doc.rust-lang.org/collections/string/struct.String.html#method.as_str)メソッドを呼び出します。 – c0g

    関連する問題