5

次のコードがあります

extern crate rand;
use rand::Rng;

pub struct Randomizer {
    rand: Box<Rng>,
}

impl Randomizer {
    fn new() -> Self {
        let mut r = Box::new(rand::thread_rng()); // works
        let mut cr = Randomizer { rand: r };
        cr
    }

    fn with_rng(rng: &Rng) -> Self {
        let mut r = Box::new(*rng); // doesn't work
        let mut cr = Randomizer { rand: r };
        cr
    }
}

fn main() {}

それは不平を言う

error[E0277]: the trait bound `rand::Rng: std::marker::Sized` is not satisfied
  --> src/main.rs:16:21
   |
16 |         let mut r = Box::new(*rng);
   |                     ^^^^^^^^ `rand::Rng` does not have a constant size known at compile-time
   |
   = help: the trait `std::marker::Sized` is not implemented for `rand::Rng`
   = note: required by `<std::boxed::Box<T>>::new`

がこれを on に課さないのに、なぜSizedonRngが必要なのか理解できません。Box<T>T

4

3 に答える 3

6

トレイトとバウンドについての詳細Sized- これはかなり特別なトレイトであり、すべての関数に暗黙的に追加されます。そのため、 のプロトタイプにリストされていませんBox::new

fn new(x: T) -> Box<T>

値 (または移動) で受け取ることに注意してください。そのxため、関数を呼び出すだけでも、その大きさを知る必要があります。

対照的に、Box型自体は必要ありませSized。(再び特別な) 特性 bound を使用します。これは、「デフォルトの境界?Sizedをオプトアウトする」ことを意味します。Sized

pub struct Box<T> where T: ?Sized(_);

よく見るBoxと、サイズのない型でを作成する方法が 1 つあります。

impl<T> Box<T> where T: ?Sized
....
    unsafe fn from_raw(raw: *mut T) -> Box<T>

そのため、安全でないコードから、生のポインターから作成できます。それ以降、すべての通常のことが機能します。

于 2016-08-30T07:33:14.337 に答える
3

問題は実際には非常に単純です。特性オブジェクトがあり、この特性オブジェクトについて知っていることは次の 2 つだけです。

  • 利用可能なメソッドのリスト
  • そのデータへのポインタ

このオブジェクトを別のメモリ ロケーション (ここではヒープ上) に移動するように要求すると、重大な情報が 1 つ不足しています。そのサイズです。

どのくらいのメモリを予約する必要があるかをどのように知るつもりですか? 何ビット移動しますか?

オブジェクトが の場合Sized、この情報はコンパイル時に認識されるため、コンパイラはそれを「挿入」します。ただし、特性オブジェクトの場合、この情報は (残念ながら) 不明であるため、これは不可能です。

この情報を利用可能にし、ポリモーフィックな移動/クローンを利用できるようにすることは非常に便利ですが、これはまだ存在せず、これまでのところ提案を覚えておらず、コストがいくらになるかわかりません (用語でメンテナンス、実行時のペナルティ、...)。

于 2016-08-30T00:07:16.787 に答える