web-dev-qa-db-ja.com

何が「特性オブジェクト」になるのですか?

最近のRust変更により「特性オブジェクト」がより目立つようになりましたが、私が実際に何かを特性オブジェクトにするものについてははっきりと理解していません。特に1つの変更は 今後の変更 特性オブジェクトが特性実装を内部タイプに転送できるようにします。

特性Fooが与えられた場合、Box<Foo>は特性オブジェクトです。 &Fooトレイトオブジェクトも? RcArcなどの他のスマートポインターについてはどうですか?特性オブジェクトとして数える独自のタイプをどのように作成できますか?

reference は、特性オブジェクトに一度言及するだけで、定義のようなものはありません。

43
Shepmaster

トレイトへのポインタがある場合、トレイトオブジェクトがあります。 BoxArcRcおよび参照&はすべて、その核となるポインタです。 「特性オブジェクト」を定義するという点では、それらは同じように機能します。

「特性オブジェクト」は、Rustの 動的ディスパッチ に対する見解です。以下は、トレイトオブジェクトが何であるかを示すのに役立つ例です。

// define an example struct, make it printable
#[derive(Debug)]
struct Foo;

// an example trait
trait Bar {
    fn baz(&self);
}

// implement the trait for Foo
impl Bar for Foo {
    fn baz(&self) { println!("{:?}", self) }
}

// This is a generic function that takes any T that implements trait Bar.
// It must resolve to a specific concrete T at compile time.
// The compiler creates a different version of this function
// for each concrete type used to call it so &T here is NOT
// a trait object (as T will represent a known, sized type
// after compilation)
fn static_dispatch<T>(t: &T) where T:Bar {
    t.baz(); // we can do this because t implements Bar
}

// This function takes a pointer to a something that implements trait Bar
// (it'll know what it is only at runtime). &dyn Bar is a trait object.
// There's only one version of this function at runtime, so this
// reduces the size of the compiled program if the function
// is called with several different types vs using static_dispatch.
// However performance is slightly lower, as the &dyn Bar that 
// dynamic_dispatch receives is a pointer to the object +
// a vtable with all the Bar methods that the object implements.
// Calling baz() on t means having to look it up in this vtable.
fn dynamic_dispatch(t: &dyn Bar) {
    // ----------------^
    // this is the trait object! It would also work with Box<dyn Bar> or 
    // Rc<dyn Bar> or Arc<dyn Bar>
    //
    t.baz(); // we can do this because t implements Bar
}

fn main() {
    let foo = Foo;
    static_dispatch(&foo);
    dynamic_dispatch(&foo);
}

さらなる参照のために、Rustブック-/の優れた 特性オブジェクトの章があります

62
Paolo Falabella

短い回答:オブジェクトセーフの特性を特性オブジェクトにしか作成できません。

Object-Safe Traits:具体的なタイプの実装に解決されない特性。実際には、トレイトがオブジェクトセーフかどうかを決定する2つのルールがあります。

  1. 戻り値の型はSelfではありません。
  2. ジェネリック型パラメーターはありません。

これらの2つのルールを満たす任意の特性を、特性オブジェクトとして使用できます。

オブジェクトセーフなトレイトの例は、トレイトオブジェクトとして使用できます。

trait Draw {
    fn draw(&self);
}

トレイトオブジェクトとして使用できないトレイトの例:

trait Draw {
    fn draw(&self) -> Self;
}

詳細な説明: https://doc.Rust-lang.org/book/second-edition/ch17-02-trait-objects.html

3
Vinod Patel