It seems that the Rust compiler has different behaviour on where
clauses.
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();
}
With a where
clause it works fine, prints:
Nop
Hello, 42
If I remove the where
clause from sub::set_ff()
the Rust compiler reports errors E0277
and 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();
}
I thought it should work fine, but the compiler reports an error instead:
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 `[closure@<anon>:41:17: 41:31 f:_]`
Why does the Rust complier require 'static
and Sized
in the second one and why does the first one work?
My OS and Rust versions:
➜ ~ 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)