我写了以下代码:
use std::io::{IoResult, Writer};
use std::io::stdio;
fn main() {
let h = |&: w: &mut Writer| -> IoResult<()> {
writeln!(w, "foo")
};
let _ = h.handle(&mut stdio::stdout());
}
trait Handler<W> where W: Writer {
fn handle(&self, &mut W) -> IoResult<()>;
}
impl<W, F> Handler<W> for F
where W: Writer, F: Fn(&mut W) -> IoResult<()> {
fn handle(&self, w: &mut W) -> IoResult<()> { (*self)(w) }
}
Run Code Online (Sandbox Code Playgroud)
然后rustc
在我的终端:
$ rustc writer_handler.rs
writer_handler.rs:8:15: 8:43 error: the trait `core::marker::Sized` is not implemented for the type `std::io::Writer`
writer_handler.rs:8 let _ = h.handle(&mut stdio::stdout());
^~~~~~~~~~~~~~~~~~~~~~~~~~~~
writer_handler.rs:8:15: 8:43 error: the trait `core::marker::Sized` is not implemented for the type `std::io::Writer`
writer_handler.rs:8 let _ = h.handle(&mut stdio::stdout());
^~~~~~~~~~~~~~~~~~~~~~~~~~~~
Run Code Online (Sandbox Code Playgroud)
为什么Writer
需要实施Sized
?在我看来,Sized
不需要.在保持trait Handler
这种通用论证的同时我应该做些什么?
在Rust 1.0中,这个类似的代码会产生同样的问题:
use std::io::{self, Write};
fn main() {
handle(&mut io::stdout());
}
fn handle(w: &mut Write) -> io::Result<()> {
handler(w)
}
fn handler<W>(w: &mut W) -> io::Result<()>
where
W: Write,
{
writeln!(w, "foo")
}
Run Code Online (Sandbox Code Playgroud)
有错误:
error[E0277]: the trait bound `std::io::Write: std::marker::Sized` is not satisfied
--> src/main.rs:8:5
|
8 | handler(w)
| ^^^^^^^ `std::io::Write` does not have a constant size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `std::io::Write`
= note: required by `handler`
Run Code Online (Sandbox Code Playgroud)
huo*_*uon 36
的Sized
特点是比较特殊的,如此特别,在大多数情况下,势必对类型参数的默认值.它表示在编译时已知固定大小的值,如u8
(1个字节)或&u32
(64位指针平台上的8个字节)等.这些值很灵活:它们可以放在堆栈上并移到堆上并且通常按值传递,因为编译器知道它需要多少空间.
未调整大小的类型受到更多限制,并且类型的值Writer
未调整大小:它抽象地表示实现的某些未指定类型,Writer
而不知道实际类型是什么.由于实际类型未知,因此无法知道大小:某些大型是Writer
s,有些是小型.Writer
是特征对象的一个示例,此时,它只能出现在指针后面的已执行代码中.常见的例子包括&Writer
,&mut Writer
或Box<Writer>
.
这解释了为什么Sized
是默认值:它通常是人们想要的.
在任何情况下,对于你的代码,这是因为你正在使用handle
而出现h
,这是一个Fn(&mut Writer) -> IoResult<()>
.如果我们将这与我们发现的F: Fn(&mut W) -> IoResult<()>
类型相匹配,那就是我们尝试使用trait对象,而不是某种具体类型.这是非法的,因为trait和impl中的参数都默认为有一个绑定,如果我们手动覆盖它然后一切正常:Handle
W = Writer
handle
&mut Writer
&mut W
W
W
Sized
?Sized
use std::io::{IoResult, Writer};
use std::io::stdio;
fn main() {
let h = |&: w: &mut Writer| -> IoResult<()> {
writeln!(w, "foo")
};
let _ = h.handle(&mut stdio::stdout());
}
trait Handler<W: ?Sized> where W: Writer {
fn handle(&self, &mut W) -> IoResult<()>;
}
impl<W: ?Sized, F> Handler<W> for F
where W: Writer, F: Fn(&mut W) -> IoResult<()> {
fn handle(&self, w: &mut W) -> IoResult<()> { (*self)(w) }
}
Run Code Online (Sandbox Code Playgroud)
而对于Rust 1.0代码:
use std::io::{self, Write};
fn main() {
handle(&mut io::stdout());
}
fn handle(w: &mut Write) -> io::Result<()> {
handler(w)
}
fn handler<W: ?Sized>(w: &mut W) -> io::Result<()>
where
W: Write,
{
writeln!(w, "foo")
}
Run Code Online (Sandbox Code Playgroud)
我还写了一篇关于Sized
和特征对象的博客文章,其中有一些细节.
首先,请注意这h
是一种实现的类型Fn(&mut Writer) -> IoResult<()>
.
h.handle
正被召唤; 这个要看的话,在Handler
这里实施W
是Writer
-注意的是仔细:W 是 Writer
,一个无胶式.该&mut stdio::stdout()
因此将被强制转换为&mut Writer
特征的对象.这在理论上非常好,但是当被带回实施时就会倒塌.当涉及到约束时,默认情况下它们是大小的,因此它会抱怨,Writer
您尝试分配的值W
不是大小.
这里有两个主要解决方案:
切换到使用具体的编写器类型,h
以便您处理大小的类型:
use std::io::{IoResult, Writer, stdio, LineBufferedWriter};
use std::io::stdio::StdWriter;
fn main() {
let h = |&: w: &mut LineBufferedWriter<StdWriter>| -> IoResult<()> {
writeln!(w, "foo")
};
let _ = h.handle(&mut stdio::stdout());
}
trait Handler<W> where W: Writer {
fn handle(&self, &mut W) -> IoResult<()>;
}
impl<W, F> Handler<W> for F
where W: Writer, F: Fn(&mut W) -> IoResult<()> {
fn handle(&self, w: &mut W) -> IoResult<()> { (*self)(w) }
}
Run Code Online (Sandbox Code Playgroud)允许W
成为未定义的类型.这是可以接受的,因为您只能通过引用使用它&mut W
.如果您希望将其用作裸型,例如W
按价值计算的方法,则不会这样做.
use std::io::{IoResult, Writer};
use std::io::stdio;
fn main() {
let h = |&: w: &mut Writer| -> IoResult<()> {
writeln!(w, "foo")
};
let _ = h.handle(&mut stdio::stdout());
}
trait Handler<W: ?Sized> where W: Writer {
fn handle(&self, &mut W) -> IoResult<()>;
}
impl<W: ?Sized, F> Handler<W> for F
where W: Writer, F: Fn(&mut W) -> IoResult<()> {
fn handle(&self, w: &mut W) -> IoResult<()> { (*self)(w) }
}
Run Code Online (Sandbox Code Playgroud)我会建议支持一个unsized,W
即使你没有在这种情况下使用它 - 没有理由它需要大小.