Rustで引数型と戻り値型がSizedでなくてもよい条件

過去の記事Sizedについて説明したが、関数の引数と戻り値についてはやや直感に反する条件が適用されているので説明する。

trait Foo {
    fn f(x: str) -> str; // OK
    // fn g(x: str) -> str { x } // error
}
fn h(_: str) {} // OK
// fn i(x: str) -> str { x } // error
fn j(ref x : str) {} // OK, but no way to call it
fn main() {
}

この規則は一見すると重箱的な問題のように見えるが、実は FnOnce トレイトを見ると実際に活用されていることがわかる。

pub trait FnOnce<Args> {
    type Output;
    extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
    //                              ^^^^ Self : ?Sized
}

トレイトの Self 引数だけは暗黙の Sized 境界が適用されないため、ここでは Self: ?Sized である。(関連型は Sized が適用される。)

この関数に Self: Sized 境界が必要ないのは、上記の条件のためである。