"Sized is not implemented" 是什么意思?
What does "Sized is not implemented" mean?
我写了下面的代码:
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`
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>
首先,请注意 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) }
}
允许 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) }
}
我建议支持未调整大小的 W
,即使在这种情况下您不使用它——没有理由 需要 调整大小。
Sized
trait 非常特殊,在大多数情况下它是类型参数的默认绑定。它表示在编译时具有已知固定大小的值,例如 u8
(1 字节)或 &u32
(在具有 64 位指针的平台上为 8 字节)等。这些值是灵活的:它们可以被放置在堆栈上并移动到堆上,并且通常按值传递,因为编译器知道它需要多少space - 无论值在哪里。
未调整大小的类型受到更多限制,类型 Writer
的值未调整大小:它抽象地表示一些实现 Writer
的未指定类型,不知道实际类型是什么。由于不知道实际类型,因此无法知道大小:一些大类型是 Writer
s,一些小类型是。 Writer
是特征对象的一个示例,目前它只能出现在指针后面的已执行代码中。常见示例包括 &Writer
、&mut Writer
或 Box<Writer>
.
这解释了为什么 Sized
是默认值:它通常是人们想要的。
无论如何,对于您的代码,这是弹出的,因为您正在使用 handle
和 h
,这是一个 Fn(&mut Writer) -> IoResult<()>
。如果我们将此与 Handle
实现的 F: Fn(&mut W) -> IoResult<()>
类型相匹配,我们发现 W = Writer
,也就是说,我们试图将 handle
与特征对象 &mut Writer
,而不是某些具体类型 W
的 &mut 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 objects in general,其中有更多细节。
我写了下面的代码:
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`
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>
首先,请注意 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) } }
允许
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) } }
我建议支持未调整大小的 W
,即使在这种情况下您不使用它——没有理由 需要 调整大小。
Sized
trait 非常特殊,在大多数情况下它是类型参数的默认绑定。它表示在编译时具有已知固定大小的值,例如 u8
(1 字节)或 &u32
(在具有 64 位指针的平台上为 8 字节)等。这些值是灵活的:它们可以被放置在堆栈上并移动到堆上,并且通常按值传递,因为编译器知道它需要多少space - 无论值在哪里。
未调整大小的类型受到更多限制,类型 Writer
的值未调整大小:它抽象地表示一些实现 Writer
的未指定类型,不知道实际类型是什么。由于不知道实际类型,因此无法知道大小:一些大类型是 Writer
s,一些小类型是。 Writer
是特征对象的一个示例,目前它只能出现在指针后面的已执行代码中。常见示例包括 &Writer
、&mut Writer
或 Box<Writer>
.
这解释了为什么 Sized
是默认值:它通常是人们想要的。
无论如何,对于您的代码,这是弹出的,因为您正在使用 handle
和 h
,这是一个 Fn(&mut Writer) -> IoResult<()>
。如果我们将此与 Handle
实现的 F: Fn(&mut W) -> IoResult<()>
类型相匹配,我们发现 W = Writer
,也就是说,我们试图将 handle
与特征对象 &mut Writer
,而不是某些具体类型 W
的 &mut 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 objects in general,其中有更多细节。