2016-05-20 11 views
1

Rustコンパイラはwhere句で異なる動作をしているようです。 where句と特性が型として使用されていて、where句の境界として使用されていないときのエラー

mod sub { 
    use std::mem; 

    static mut FF : *const Foo = &NopFoo; 

    pub trait Foo: Send + Sync { 
     fn foo(&self); 
    } 

    pub struct NopFoo; 

    impl Foo for NopFoo { 
     fn foo(&self) { println!("Nop"); } 
    } 

    pub struct HelloFoo { 
     pub num: i64, 
    } 

    impl Foo for HelloFoo { 
     fn foo(&self) { println!("Hello, {}", self.num); } 
    } 

    pub fn set_ff<M>(make_foo: M) -> bool 
     where M: FnOnce() -> Box<Foo> // <== Here 
    { 
     unsafe { 
      FF = mem::transmute(make_foo()); 
     } 
     false 
    } 

    pub fn get_ff() -> Option<&'static Foo> { 
     Some(unsafe { &*FF }) 
    } 
} 

fn main() { 
    sub::get_ff().unwrap().foo(); 

    let f = sub::HelloFoo{num: 42}; 
    sub::set_ff(|| Box::new(f)); 

    sub::get_ff().unwrap().foo(); 
} 

Playground

、それは罰金、版画作品:私はsub::set_foo()からwhere句を削除した場合

Nop 
Hello, 42 

錆コンパイラがエラーを報告します[ E0277]および[E0308]

mod sub { 
    use std::mem; 

    static mut FF : *const Foo = &NopFoo; 

    pub trait Foo: Send + Sync { 
     fn foo(&self); 
    } 

    pub struct NopFoo; 

    impl Foo for NopFoo { 
     fn foo(&self) { println!("Nop"); } 
    } 

    pub struct HelloFoo { 
     pub num: i64, 
    } 

    impl Foo for HelloFoo { 
     fn foo(&self) { println!("Hello, {}", self.num); } 
    } 

    pub fn set_ff(make_foo: Box<Foo>) -> bool // <== Here 
    { 
     unsafe { 
      FF = mem::transmute(make_foo()); 
     } 
     false 
    } 

    pub fn get_ff() -> Option<&'static Foo> { 
     Some(unsafe { &*FF }) 
    } 
} 

fn main() { 
    sub::get_ff().unwrap().foo(); 

    let f = sub::HelloFoo{num: 42}; 
    sub::set_ff(|| Box::new(f)); 

    sub::get_ff().unwrap().foo(); 
} 

Playground

私はそれが正常に動作する必要がありますと思ったが、コンパイラが代わりにエラーを報告:

error: the trait bound `std::ops::FnOnce() -> Box<sub::Foo + 'static> + 'static: std::marker::Sized` is not satisfied [--explain E0277] 
    --> <anon>:24:19 
24 |>  pub fn set_ff(make_foo: FnOnce() -> Box<Foo>) -> bool 
    |>     ^^^^^^^^ 
note: `std::ops::FnOnce() -> Box<sub::Foo + 'static> + 'static` does not have a constant size known at compile-time 
note: all local variables must have a statically known size 

error: mismatched types [--explain E0308] 
    --> <anon>:41:17 
41 |>  sub::set_ff(|| Box::new(f)); 
    |>     ^^^^^^^^^^^^^^ expected trait std::ops::FnOnce, found closure 
note: expected type `std::ops::FnOnce() -> Box<sub::Foo + 'static> + 'static` 
note: found type `[[email protected]<anon>:41:17: 41:31 f:_]` 

はなぜ錆のコンパイラは、第1に'staticSizedを必要としないし、なぜ最初の仕事?

私のOSや錆のバージョン:

➜ ~ uname -a 
Linux laptop 4.2.0-35-generiC#40~14.04.1-Ubuntu SMP Fri Mar 18 16:37:35 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux 
➜ ~ rustc --version 
rustc 1.10.0-nightly (9c6904ca1 2016-05-18) 

答えて

6

短い答え:2つのコードが同じではない、もう一つは、実際にも、意味がありません。おそらく、最初のものが必要です。

はのは、単純な例を見てみましょう:

trait Foo { 
    fn foo(&self) {} 
} 

fn in_where<T>(x: T) 
    where T: Foo 
{ 
    x.foo() 
} 

fn in_declaration<T: Foo>(x: T) { 
    x.foo() 
} 

fn in_type(x: Foo) { 
    x.foo() 
} 

これは、一般的な宣言でバインド形質を置き、同一のケースを追加し、どこ特性失敗した場合を含み、whereを使用してオリジナルケースをキャプチャ引数の型として直接使用されます。

ここで重要な点は、最初の2つのバージョンが3番目と同じではないことです。作業バージョンでは、Foo特性を実装している限り、のいずれかのタイプの値がタイプの値に渡されることがあります。機能しないバージョンでは、それが正確に1つの型、つまり型の型自体を受け入れることが述べられています。コンパイラの状態として

:作業バージョンのいずれかが使用される場合

the trait core::marker::Sized is not implemented for the type Foo + 'static

Foo + 'static does not have a constant size known at compile-time; all local variables must have a statically known size.

、コンパイラは、使用されるすべての具象型(monomorphizationと呼ばれるプロセス)のためのコードのバージョンを生成します。型がどれだけのスペースを必要としているかを知っており、それを収容するためにスタックに適切なスペースを割り当てることができます。

しかし、特性は、特性と同じ名前ののサイズ指定されていないタイプを作成します。コンパイラは、割り当てようとする容量をは認識していないため、実際にその関数のマシンコードを生成することは不可能です。

特性タイプは使用できますが、間接レベル(特性オブジェクト)でのみ使用できます。 2つの一般的な例は&FooBox<Foo>です。これらの両方とも、間接的にポインタを介して基礎となる形質にアクセスします。ポインタは既知のサイズを持つため、コードを生成することができます。

fn in_type_ref(x: &Foo) { 
    x.foo() 
} 

fn in_type_box(x: Box<Foo>) { 
    x.foo() 
} 

さらにリーディング:


Why does the Rust complier require 'static

それはしません。有効期間が指定されていないため、暗黙的に'staticが特性タイプに追加されています。引き数の完全な型はFoo + 'staticです。

+0

私はこの質問が以前に答えられたことを知っていますが、私は前のケースを見つけることができません。発見されたときは重複して自由に閉じるようにしてください。 – Shepmaster

+0

greateの回答ありがとうございます!それは本当にたくさんの助けになります! – NeilShen

関連する問題