2017-07-13 14 views
6

私はしばしばnewtypeパターンを使いますが、私はmy_type.0.call_to_whatever(...)と書いてうんざりです。私はDerefの特性を実装しようとしているのですが、単純なコードを書くことができるので、私のnewtypeはあたかも基底型であるかのように使うことができるからです。Derefをnewtypeに実装することは悪い習慣と考えられますか?

use std::ops::Deref; 

type Underlying = [i32; 256]; 
struct MyArray(Underlying); 

impl Deref for MyArray { 
    type Target = Underlying; 

    fn deref(&self) -> &Self::Target { 
     &self.0 
    } 
} 

fn main() { 
    let my_array = MyArray([0; 256]); 

    println!("{}", my_array[0]); // I can use my_array just like a regular array 
} 

これは良いか悪い習慣ですか?どうして?欠点は何ですか?

答えて

7

悪い練習だと思います。それは暗黙のうちに参照があるたび基になる型として使用することができます - それは問題だ、いくつかの状況

における根本的なタイプであるかのように私は私のnewtypeを使用することができますので、

DerefMutを実装すると、変更可能な参照が必要な場合にも適用されます。

基礎となるタイプとは何があり、何が利用できないのかは制御できません。すべてがです。あなたの例では、人々がas_ptrに電話することを許可しますか? sortはどうですか?彼らができるので、私はあなたがしたいことを願っています!あなたができることすべてについて

は、メソッドを上書きしようとする試みであるが、彼らはまだ存在する必要があります:

impl MyArray { 
    fn as_ptr(&self) -> *const i32 { 
     panic!("No, you don't!") 
    } 
} 

をしても、その後、彼らはまだ(<[i32]>::as_ptr(&*my_array);)明示的に呼び出すことができます。

コードの再利用に継承を使用することは悪い習慣であると私が信じるのと同じ理由で悪い習慣と考えています。あなたの例では、基本的に配列から継承しています。これは、とあり-概念をオブジェクト指向モデリングから戻っに来る

class MyArray < Array 
    # ... 
end 

:私は次のRubyのようなものを書くことがありませんでした。 はアレイですか?配列がの場合はどこでもを使用できますか?それは、消費者が壊れることができないようにオブジェクトが維持すべきという前提条件を持っていますか?

が、私は他の言語で同様my_type.0.call_to_whatever(...)

を書くの疲れている、私は正解が相続オーバー組成物であると信じています。あなたは、コールを転送のnewtypeにメソッドを作成する必要がある場合:

impl MyArray { 
    fn call_to_whatever(&self) { self.0.call_to_whatever() } 
} 

ルーストに、これは痛みを伴う可能主なものは、委任の欠如です。あなたがDeref/DerefMutを使用する必要があるとき架空の委任構文だから

impl MyArray { 
    delegate call_to_whatever -> self.0; 
} 

のようなものだろうか?私は、スマートポインタを実装しているときだけ意味があると主張します。


事実上、私はないは、私が唯一のまたは大多数寄稿していたプロジェクトで公開されているnewtypesため使用Deref/DerefMutを行う話します。これは私が自分自身を信じて、私が意味することをよく知っているからです。委任構文が存在する場合、私はしません。

+1

私は少なくとも「Deref」に関して同意しなければなりません。私のnewtypeの大部分はファンシーコンストラクタとしてのみ存在するため、一定の不変条件を満たすという静的保証でデータを渡すことができます。つまり、オブジェクトが構築されたら、もはやnewtypeは本当に気にしません。基礎データのみです。どこでもパターンを一致させることは雑音に過ぎず、私が心配するかもしれないすべての方法を委任することも同様です。私は、型がDerefMutではなくDerefMutを実装するのは驚くかもしれないと考えていますが、理由のために別の特性です... – ildjarn

+1

@ indjarn * 'DerefMut'を実装すると、newtypeフィールドの可視性にかかわらず、誰でも簡単にそれらを変更できるので、不変量を静的に保証することはできません。 'Deref'だけを実装すれば、人々はあなたのデータを突き止めることができます。これにより重大な損害は発生しませんが、公開する必要があるAPIよりも広いAPIを提示することがよくあります。 – Shepmaster

+0

"*これは重大な損害を引き起こしてはいけませんが、あなたが公開する必要があるAPIよりも広いAPIを提供することがあります。*" std :: str'以上のIMO;例えば、あなたはしばしば、その事実を曖昧にする(/抽象化しようとする)ことは無意味ですが、維持する厳格な不変条件(UTF-8)があるプリミティブ型のシーケンスを扱うことがあります。私はそれについて強く感じない。私はちょうど "悪い練習"がかなり強くそれを入れているように感じる。 : - ](編集: 'deref_mut'を安全にできないなら、おそらく' Deref'sansの 'DerefMut'という難問がないので強く感じるでしょう) – ildjarn

関連する問題