什么“大小没有实现”是什么意思?

时间:2015-01-20 11:27:32

标签: rust

我写了以下代码:

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) }
}

然后在我的终端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());
                                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~

为什么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")
}

错误:

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`

2 个答案:

答案 0 :(得分:36)

Sized特征相当特殊,特别是在大多数情况下它是类型参数的默认绑定。它表示在编译时已知固定大小的值,如u8(1字节)或&u32(在具有64位指针的平台上为8个字节)等。这些值很灵活:它们可以被放置在堆栈上并移动到堆上,并且通常按值传递,因为编译器知道它需要多少空间。

不是大小的类型受到更多限制,类型Writer的值不是大小的:它抽象地表示一些实现Writer的未指定类型,不了解实际类型是什么。由于实际类型不为人所知,因此无法知道大小:某些大类型是Writer,有些是小类型。 Writer是特征对象的一个​​示例,此时,它只能出现在指针后面的已执行代码中。常见示例包括&Writer&mut WriterBox<Writer>

这解释了为什么Sized是默认值:它通常是人们想要的。

在任何情况下,对于您的代码,这会弹出,因为您使用handle h Fn(&mut Writer) -> IoResult<()>F: Fn(&mut W) -> IoResult<()>。如果我们将Handle类型与W = Writer类型匹配,我们会发现handle,即我们正在尝试将&mut Writer与特征对象一起使用对于某些具体类型&mut WW,而不是W。这是非法的,因为特征和impl中的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) } } 手动覆盖它,那么一切正常:

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")
}

对于Rust 1.0代码:

{{1}}

我还写了一个blog post about Sized和特征对象,它们有更多的细节。

答案 1 :(得分:5)

首先,请注意h是一种实现Fn(&mut Writer) -> IoResult<()>的类型。

正在呼叫

h.handle;这取决于Handler W Writer Writer的实施情况 - 请注意:W &mut stdio::stdout(),一种未经过类型化的类型。因此,&mut Writer将被转换为Writer特征对象。这在理论上非常好,但是当被带回实施时就会倒塌。当涉及到约束时,默认情况下它们会被调整大小,因此它会抱怨W,您尝试为h分配的值不是大小。

这里有两个主要解决方案:

  1. 切换到使用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) } } 上的具体编写器类型,以便处理大小类型:

    W
  2. 允许&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) } } 的方法,它不会。

    W
  3. 我建议支持未经过身份验证的{{1}},即使您在这种情况下不使用它 - 也没有理由需要进行调整。