配列における Default トレイトの奇妙な制限について。
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 の場合の実装を特殊化して例外にできる)。しかし、現状では specialization や min_specialization など、まだ RFC への提案段階にある。