この特性定義はうまくコンパイルされます:
trait Works {
fn foo() -> Self;
}
ただし、これによりエラーが発生します。
trait Errors {
fn foo() -> Option<Self>;
}
error[E0277]: the size for values of type `Self` cannot be known at compilation time
--> src/lib.rs:6:5
|
6 | fn foo() -> Option<Self>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `Self`
= note: to learn more, visit <https://doc.Rust-lang.org/book/second-edition/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
= help: consider adding a `where Self: std::marker::Sized` bound
= note: required by `std::option::Option`
とともに : Sized
スーパートレイトバウンド、動作します。
特性のSelf
タイプが自動的にSized
にバインドされないことを知っています。そして私はOption<Self>
は、サイズ変更されない限り(スタックを介して)返されません(そのため、Self
のサイズが必要になります)。ただし、戻り値の型としてSelf
も同様です。サイズを指定しない限り、スタックに格納することもできません。
最初の特性定義がそのエラーをすでにトリガーしていないのはなぜですか?
(この質問 は関連していますが、私が正確に質問に答えることはできません-理解していなければ)
Option
の問題は氷山の一角に過ぎず、他の人はすでにそのことを少し説明しています。 コメント内の質問 について詳しく説明したいと思います。
Self
がSized
ではなく、fnfoo() -> Self
を実装する方法はありますか?それを行う方法がない場合、Self
バインドなしでSized
を返すことを許可する意味が見当たらないためです。
その方法では、2つの問題があるため、(少なくとも現在のところ)トレイトをトレイトオブジェクトとして利用することは実際には不可能です。
self
パラメータを取らないメソッドは、メソッドテーブルへのポインタを取得する方法がないため、呼び出すことができません。
これにより、トレイトはオブジェクトセーフではなくなります。つまり、トレイトからトレイトオブジェクトを作成することはできません。
ただし、他の用途には完全に使用できます。
trait Works {
fn foo() -> Self;
}
#[derive(PartialEq, Debug)]
struct Foo;
impl Works for Foo {
fn foo() -> Self {
Foo
}
}
fn main() {
assert_eq!(Foo::foo(), Foo);
}