配列における Default トレイトの奇妙な制限について。

背景

Const Generics

Const Generics は定数をジェネリクス型として扱えるようにする機能である。この機能は Rust 1.47.0 で配列について先行採用、Rust 1.51.0 で全体に採用された。

配列への適用

Const Generics により、配列のトレイト実装も任意の要素数を扱えるようになった。

例えば、現在の Debug トレイトは以下のように定義されている。

impl<T, const N: usize> Debug for [T; N] where T: Debug

一方、以前のそれは以下のような実装が複数あり、要素数 32 が上限だった。

impl<T> Debug for [T; 32] where T: Debug

奇妙な制限

以上のように、各トレイトは任意の要素数の配列に対応できるようになった。

しかし、Default トレイトだけはまだそうなっていない。

原因

Default トレイトの場合、要素数が 0 だと境界 T: Default が必要ない。

つまり、以下の実装がある。

impl<T> Default for [T; 0]

そして、これは以下の実装と衝突してしまう。

impl<T, const N: usize> Default for [T; N] where T: Default

サンプル

以下では、未対応の要素数の配列 [i32; 64]default メソッドを使っている。


fn main() {
    let arr1 = <[i32; 64]>::default();
    let arr2 = std::iter::repeat_n(i32::default(), 64);
    assert!(arr1.into_iter().eq(arr2))
}

error[E0599]: no function or associated item named `default` found for array `[i32; 64]` in the current scope
 --> src\main.rs:2:29
  |
2 |     let arr1 = <[i32; 64]>::default();
  |                             ^^^^^^^ function or associated item not found in `[i32; 64]`

解決策

単純なメソッド呼出なら『配列の初期化』で紹介する各種方法で代替できるだろう。

将来の展望

この問題は Rust に特殊化が導入されれば解決するだろう (N が 0 の場合の実装を特殊化して例外にできる)。しかし、現状では specializationmin_specialization など、まだ RFC への提案段階にある。