48910


現在ironフレームワークを用いたWebプログラミングを勉強しています。  
その中でセッション周りの実装の際に、ironが提供するトレイトを実装している型をキーにしていろいろやり取りをするのですが、以下のようにわかりやすく実装しなおそうと思っています。（説明が長くなりますすみません...）

* * *

セッションを扱うには、自身で定義した2つのstruct（`Session`,
`SessionKey`とします）に対し、ironクレートによって提供されている`typemap::Key`トレイトを次のように適用します。

[code]

    struct Session; // セッションデータとして扱う構造体（自分はHashMapを1つ持つタプル構造体にしています）
    struct SessionKey; // 関数を呼ぶ際、扱う型を決定するのに使用します
                       // 例）get_ref::<SessionKey>() -> &Sessionが返される
    
    impl typemap::Key for SessionKey {
        type Value = Session;
    }
    
[/code]

このようにimplすることで、上の例のように`SessionKey`をキーにして`Session`構造体をやり取りします。

わかりやすさのために、`typemap::Key, Value`ではなく次のような名前で扱おうと考えています。

[code]

    trait SessionType {
        type SessionData;
    }
    
[/code]

という名前で定義したトレイトと関連型を、

[code]

    impl SessionType for SessionKey {
        type SessionData = Session;
    }
    
[/code]

同じようにimplします。  
これによって、`typemap::Key`のimplは内部に隠しつつ、わかりやすい名前で扱えないかと考えています。  
なので次のように実装しました。

[code]

    extern crate iron;
    use iron::typemap;
    
    struct Session;
    struct SessionKey;
    
    // こっちを使いたい
    trait SessionType {
        type SessionData;
    }
    // このように実装したい（見える部分）
    impl SessionType for SessionKey {
        type SessionData = Session;
    }
    
    // こちらを追加（見えない部分）
    impl<S: SessionType> typemap::Key for S {
        type Value = <S as SessionType>::SessionData;
    }
    
    fn main(){
        // ...
    }
    
[/code]

[code]

    impl<S: SessionType> typemap::Key for S {
        type Value = <S as SessionType>::SessionData;
    }
    
[/code]

これは、`SessionType`トレイトを実装している全ての構造体に対し、`typemap::Key`を実装します。またその構造体に`SessionType`トレイトを実装した際の`type
Session`に指定した型`<S as
SessionType>::SessionData`を`Value`に指定します。こうすることで`typemap::Key`の実装を見える部分で行う必要がなくなると考えました。  
しかしエラーになります。

[code]

    error[E0210]: type parameter `S` must be used as the type parameter for some local type (e.g. `MyStruct<T>`);
    only traits defined in the current crate can be implemented for a type parameter
      --> src\main.rs:17:1
       |
    17 | / impl<S: SessionType> Key for S {
    18 | |     type Value = <S as SessionType>::Session;
    19 | | }
       | |_^
    
[/code]

このエラーの原因がわかりません。  
ちなみに

[code]

    trait Key {
        type = Value;
    }
    
[/code]

というトレイトを自分で定義し、`typemap::Key`と同じように書いた場合はエラーが出ませんでした。（しかしironの関数を利用するには`typemap::Key`の実装が必要...）  
これは`typemap::Key`が外部で定義されているから無理ということなのでしょうか？しかしエラー文からはそのように読み取れないので理由がわかりません。

長文になってしまい申し訳ありません。  
このエラーの原因と回避の仕方がわかる方いらっしゃいませんか？


CC BY-SA 4.0
2018-10-02T17:26:43.137
48909
2018-10-02T22:14:37.437
2018-10-02T17:46:08.000
29682
29682
question
rust
Rustでのエラー『type parameter `_` must be used as the type parameter for some local type』について。


> これはtypemap::Keyが外部で定義されているから無理ということなのでしょうか？

概ねそのような理由です。具体的にはOrphan
Rule(孤児規則)と呼ばれる制約に引っかかっています。自分で定義していないトレイトを自分で定義していない型に対して(今回はジェネリクスなので定義していない型も含んでいます)実装できるとすると、複数人が同じことをした場合に実装が複数存在して一貫性がなくなります。エラーメッセージに出ているように
`rustc --explain E0210` で詳しく解説されています。

日本語記事だと下記があるようです。  
参考: Rustのコヒーレンス - 簡潔なQ  
<https://qnighy.hatenablog.com/entry/2017/07/20/220000>


CC BY-SA 4.0
2018-10-02T22:14:37.437
48910
2018-10-02T22:14:37.437
22816
48909
answer