似乎Rust编译器对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();
}
Run Code Online (Sandbox Code Playgroud)
(游乐场)
有一个where条款,它工作正常,打印:
Nop
Hello, 42
Run Code Online (Sandbox Code Playgroud)
如果我where从sub::set_ff()Rust编译器报告错误中删除该子句:[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();
}
Run Code Online (Sandbox Code Playgroud)
(游乐场)
我认为它应该工作正常,但编译器报告错误:
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:_]`
Run Code Online (Sandbox Code Playgroud)
为什么编译需要除锈'static,并Sized在第二个,为什么做的第一个工作?
我的OS和Rust版本:
? ~ 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)
Run Code Online (Sandbox Code Playgroud)
简短的回答:这两段代码不相同,第二段甚至没有意义.你可能想要第一个.
让我们看一个更简单的例子:
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()
}
Run Code Online (Sandbox Code Playgroud)
这捕获了使用的原始案例where,添加了将特征绑定在泛型声明中的相同案例,并包括将特征直接用作参数类型的失败案例.
这里的关键点是,前两个版本不一样的三分之一.工作版本声明任何类型都可以通过值传递给函数,只要它实现了Foo特征即可.非工作版本声明它只接受一种类型,即特征的类型本身.
正如编译器所述:
core::marker::Sized该类型没有实现特征Foo + 'static
Foo + 'static在编译时没有已知的常量; 所有局部变量必须具有静态已知大小.
当使用其中一个工作版本时,编译器会为所使用的每种具体类型生成一个代码版本(称为单态化的过程).它知道该类型需要多少空间,并且可以在堆栈上适当地分配空间以容纳它.
但是,特征会创建与特征同名的unsized类型.编译器不知道要分配多少空间,因此实际生成该函数的机器代码是不可能的.
可以使用特征类型,但只能通过间接级别(特征对象).两个常见的例子是&Foo和Box<Foo>.这两个都通过指针间接访问底层特征.由于指针具有已知大小,因此可以生成代码.
fn in_type_ref(x: &Foo) {
x.foo()
}
fn in_type_box(x: Box<Foo>) {
x.foo()
}
Run Code Online (Sandbox Code Playgroud)
进一步阅读:
为什么Rust编译器需要
'static
它没有.'static由于您尚未指定生命周期,因此在特征类型中添加了隐式绑定.参数的完整类型是Foo + 'static.
| 归档时间: |
|
| 查看次数: |
1279 次 |
| 最近记录: |