似乎Rust编译器在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();
}
子句上有不同的行为。
where
使用Nop
Hello, 42
子句,它工作正常,打印:
where
如果我从sub::set_ff()
删除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();
}
子句,则Rust编译器报告错误:[E0277]和[E0308]
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:_]`
我认为它应该可以正常工作,但编译器会报告错误:
'static
为什么Rust编译器在第二个编译器中需要Sized
和➜ ~ 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)
,为什么第一个编译器有效?
我的操作系统和Rust版本:
$stateProvider
.state('home', {
url: '/',
views: {
'': {
templateUrl: 'templates/app.tpl.html',
},
'section1': {
controller: 'Section1Controller as vm',
templateUrl: 'templates/section1.tpl.html'
},
'section2': {
controller: 'Section2Controller as vm',
templateUrl: 'templates/section2.tpl.html'
},
'section3': {
controller: 'Section3Controller as vm',
templateUrl: 'templates/section3.tpl.html'
},
'section4': {
controller: 'Section4Controller as vm',
templateUrl: 'templates/section4.tpl.html'
}
}
})
.state('page2', {
url: '/page2',
views: {
'': {
templateUrl: 'templates/page2.tpl.html',
},
'section1': {
controller: 'Section1Controller as vm',
templateUrl: 'templates/section1.tpl.html'
},
'section2': {
controller: 'Section2Controller as vm',
templateUrl: 'templates/section2.tpl.html'
},
'section3': {
controller: 'Section3Controller as vm',
templateUrl: 'templates/section3.tpl.html'
}
}
})
答案 0 :(得分:6)
简短的回答:这两段代码不相同,第二段甚至没有意义。你可能想要第一个。
让我们看一个更简单的例子:
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
的原始案例,添加了将特征限制在泛型声明中的相同案例,并包括将特征直接用作参数类型的失败案例。
这里的关键点是前两个版本与不一样。工作版本声明任何类型可以通过值传递给函数,只要它实现Foo
特征即可。非工作版本声明它只接受一种类型,即特征的类型本身。
正如编译器所述:
特征
实施core::marker::Sized
未针对类型Foo + 'static
Foo + 'static
在编译时没有已知的常量;所有局部变量必须具有静态已知的大小。
当使用其中一个工作版本时,编译器会为所使用的每个具体类型生成一个代码版本(一个名为 monomorphization 的过程)。它知道该类型需要多少空间,并且可以在堆栈上适当地分配空间以容纳它。
但是,特征会创建与特征同名的 unsized type 。编译器不知道要分配多少空间,因此实际上不可能为该函数生成机器代码。
可以使用特征类型,但只能通过间接级别(特征对象)。两个常见示例是&Foo
和Box<Foo>
。这两个都通过指针间接访问底层特征。由于指针具有已知大小,因此可以生成代码。
fn in_type_ref(x: &Foo) {
x.foo()
}
fn in_type_box(x: Box<Foo>) {
x.foo()
}
进一步阅读:
为什么Rust编译器需要
'static
没有。由于您尚未指定生命周期,因此在特征类型中添加了隐式'static
绑定。参数的完整类型为Foo + 'static
。