【问题标题】:What does "Sized is not implemented" mean?“未实施大小”是什么意思?
【发布时间】:2015-03-18 14:46:26
【问题描述】:

我写了以下代码:

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());
                                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~

为什么实现Sized 需要这个Writer?在我看来,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`

Rust 的更高版本有错误

error[E0277]: the size for values of type `dyn std::io::Write` cannot be known at compilation time
  --> src/main.rs:8:13
   |
8  |     handler(w)
   |             ^ doesn't have a size known at compile-time
...
11 | fn handler<W>(w: &mut W) -> io::Result<()>
   |    ------- - required by this bound in `handler`
   |
   = help: the trait `std::marker::Sized` is not implemented for `dyn std::io::Write`
   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>

【问题讨论】:

    标签: rust


    【解决方案1】:

    首先,请注意h 是实现Fn(&amp;mut Writer) -&gt; IoResult&lt;()&gt; 的类型。

    h.handle 正在被调用;那么,这取决于Handler 实现,其中WWriter——请注意:W Writer,一个未调整大小的类型。因此,&amp;mut stdio::stdout() 将被强制转换为 &amp;mut Writer 特征对象。这在理论上都很好,但是当回到实现时就会失败。当涉及到约束时,默认情况下会调整它们的大小,因此它会抱怨您尝试为 W 分配的值 Writer 没有调整大小。

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

    1. 切换到在 h 上使用具体的 writer 类型,以便您处理大小合适的类型:

      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) }
      }
      
    2. 允许W 为未调整大小的类型。这是可以接受的,因为您只能通过参考 &amp;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,即使您在这种情况下不使用它——没有理由需要调整大小。

    【讨论】:

      【解决方案2】:

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

      没有调整大小的类型受到更多限制,Writer 类型的值没有调整大小:它抽象地表示一些实现Writer 的未指定类型,不知道实际类型是什么.由于不知道实际类型,因此无法知道大小:一些大型类型是Writers,一些小型类型是。 Writer 是 trait 对象的一个​​例子,目前它只能出现在指针后面的执行代码中。常见示例包括&amp;Writer&amp;mut WriterBox&lt;Writer&gt;

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

      无论如何,对于您的代码,这是因为您使用 handleh,这是一个 Fn(&amp;mut Writer) -&gt; IoResult&lt;()&gt;。如果我们将其与实现HandleF: Fn(&amp;mut W) -&gt; IoResult&lt;()&gt; 类型相匹配,我们会发现W = Writer,也就是说,我们正在尝试将handle 与特征对象&amp;mut Writer 一起使用,而不是&amp;mut W一些具体类型W。这是非法的,因为 trait 和 impl 中的 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) }
      }
      

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

      我还写了一个 blog post about Sized 和一般的 trait 对象,其中包含更多细节。

      【讨论】:

      • 非常感谢。我确认您的代码工作正常。我的理解是 Sized 需要实现,因为 rust 运行时需要知道它在调用堆栈上占用了多少字节。所以,我打算使用指针来避免未知大小的类型,在这种情况下&amp;mut...我不明白我的代码中需要Sized
      • 它不是必需的,正如第二组代码工作所展示的那样,这只是一个默认问题:编译器默认设置Sized绑定那个类型参数,因为这是编译器为几乎所有类型参数定义的。
      • 哦。我得到了它!很抱歉,我没有完全理解您的回答:“impl 默认具有 Sized 绑定”。再次感谢 dbaupp!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-19
      • 1970-01-01
      • 1970-01-01
      • 2020-12-19
      • 2020-07-01
      • 2020-05-03
      相关资源
      最近更新 更多