要するに
- 言語上の抽象型の扱い方の話
- 抽象化の処理に最小限のコストしかかからないという意味
- Rustでは静的ディスパッチと動的ディスパッチを使い分けられるので,他の言語に比べて余計なコストがかからない,ぐらいの意味
もう少し詳しく
Javaとかの抽象化は実行時に抽象クラスを継承した型のインスタンスで処理するので実行時オーバーヘッドがある
Rustだと通常の抽象型(trait)は,コンパイル時に具体的な型に置換される (静的ディスパッチ)
- すると実行時のオーバーヘッドがかからない
1fn print_hash<T: Hash>(t: &T) {
2 println!("the hash is {}", t.hash())
3}
4
5// Tがboolの場合,下記のような専用関数が生成される
6__print_hash_bool(&true); // originai: print_hash(&true);
7// Tがi64の場合,下記のような専用関数が生成される
8__print_hash_i64(&12_i64); // originai: print_hash(&12_i64);
- ただ静的ディスパッチだと,同じ抽象型を継承した異なる型を持つリストを扱うなどができない
- 例えば下記の
listeners
にはClickCallbackを継承したAとBを同時に突っ込めない
- 例えば下記の
1trait ClickCallback {
2 fn on_click(&self, x: i64, y: i64)
3}
4
5struct Button<T: ClickCallback> {
6 listeners: Vec<T>,
7 ...
8}
- このような場合は,実行時オーバーヘッドはかかるが動的ディスパッチ(Box)を使う
1struct Button {
2 listeners: Vec<Box<ClickCallback>>,
3 ...
4}
- すると,基本的には静的ディスパッチでオーバーヘッドなし,必要なときだけ動的ディスパッチでオーバーヘッドを許容する,というつくりになるので,他の言語より抽象化の扱いに関するコストが少ない
- というかちゃんと使い分ければ最小限のコストしか払わない=余分なコストがゼロ
- ということでゼロコスト抽象化といっているらしい
Tagged: #Rust