🦊

Rust で trait のエイリアス

2021/03/04に公開
1

名前が長すぎる trait を短くしたい

Rustを使っているときに、

Fn(i64, MyType<T>, bool, usize) -> (MyType<T>,i64)

みたいな長いtraitを何度も使いたく、traitの別名を作りたかったんですが、結構悩んだのでメモとして残しておきます。
クロージャを関数の返り値を

fn some_fn() -> impl Fn(i64, MyType<T>, bool, usize) -> (MyType<T>, i64)
{
  |/* 省略 */| {/* 省略 */}
}

ではなく

fn some_fn() -> impl LongFn<T> {
  |/* 省略 */| {/* 省略 */}
}

みたいに書きたかったので。
型のエイリアスは

type NanoSecond = u64;

のように簡単に書けるのですが、traitは調べてもなかなかわかりませんでした。また、上の例の場合、関数/クロージャごとに型が変わってしまうため、型のエイリアスを作ってもうまく行きませんでした。dynを含めた型は型エイリアスにすることはできません。

traitのエイリアスを作る

結論から言うと、次のようにやります。

trait LongFn<T>:
  Fn(i64, MyType<T>, bool, usize) -> (MyType<T>, i64) {}

impl <S, T> LongFn<T> for S where 
  S: Fn(i64, MyType<T>, bool, usize) -> (MyType<T>, i64) {}

ジェネリックでtraitを実装することで、クロージャに自動的にLongFn<T>が実装されて使うことができます (こんな書き方できるんだ...)。このようにすることで、traitのエイリアスを作ることができます。

ちなみにRust Unstableだと

trait_alias - The Rust Unstable Bookにあるように、次のようなtraitのエイリアスが提案されていました。
上のような方法があるので、今後安定化される可能性は低いでしょう。

#![feature(trait_alias)]

trait Foo = std::fmt::Debug + Send;
trait Bar = Foo + Sync;

参考

https://metareal.blog/post/2015/07/rust-trait-alias/

Discussion