LoginSignup
25

More than 5 years have passed since last update.

不要なはずの Sized を要求してくる

Last updated at Posted at 2015-01-21

分からなくて Stackoverflow で聞いてようやく理解できたのでメモを兼ねて書く。

このエラーと戦う:

error: the trait `core::marker::Sized` is not implemented for the type ...

下記のようなコードを書いた。Writer は trait なので、実行時のサイズがよく分からずコールスタックには載せられないので参照(&mut)を使おうと考えた:

use std::io::{stdio, IoResult, Writer};

#[allow(unstable)]
fn main() {
    let h = |&: w: &mut Writer| -> IoResult<()> {
        writeln!(w, "foo")
    };
    let _ = h.handle(&mut stdio::stdout());
}

trait Handler<W: Writer> {
    fn handle(&self, &mut W) -> IoResult<()>;
}

impl<W: Writer, F: Fn(&mut W) -> IoResult<()>> Handler<W> for F {
    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());
                                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to 2 previous errors

となる。要らないはずの Sized を要求されている。

Sized っていうのは「実行時にその型はどれだけメモリの確保が必要かわかっている」ってことを表現した trait で、struct には Sized が自動的に実装された状態になるが、trait には Sized が実装されない。trait では実行時にどの構造体がくる分からず、サイズが分からないからだ。

確かに Writer は trait なので Sized が実装されていない。

しかしそんなの分かっていて、そのために &mut を付けて参照にしていたのに・・・

原因

型パラメータには暗黙的に Sized が付いてくるため。

上記の例で言うと trait Handler<W>impl Handler<W> for ... は暗黙的に以下のような意味になる:

trait Handler<W: Writer + Sized> {
impl<W: Writer + Sized, F: Fn(&mut W) -> IoResult<()>> Handler<W> for F {

このように、勝手に Sized をつけてくるため、Sized がない Writer を引数にしている h を使おうとすると:

error: the trait `core::marker::Sized` is not implemented for the type `std::io::Writer`

というエラーがでてしまう。

対処方法

暗黙的に付く Sized を除くような記述をする。

それが ?Sized という trait。これは「Sized でも Sized じゃなくてもいいよ、気にしないよ」という意味の(擬似?) trait らしい。

例として挙げたコードだと下記のように修正する:

use std::io::{stdio, IoResult, Writer};

#[allow(unstable)]
fn main() {
    let h = |&: w: &mut Writer| -> IoResult<()> {
        writeln!(w, "foo")
    };
    let _ = h.handle(&mut stdio::stdout());
}

//                         ↓これ!!!!
trait Handler<W: Writer + ?Sized> {
    fn handle(&self, &mut W) -> IoResult<()>;
}

//                ↓これ!!!!
impl<W: Writer + ?Sized, F: Fn(&mut W) -> IoResult<()>> Handler<W> for F {
    fn handle(&self, w: &mut W) -> IoResult<()> {
        (*self)(w)
    }
}

こうすることで、暗黙的に付く Sized を避けられ、サイズの要求をされることなく rustc が通るようになる。

参考

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
25