Skip to content

Latest commit

 

History

History
198 lines (158 loc) · 8.25 KB

intoiterator-box-slice.md

File metadata and controls

198 lines (158 loc) · 8.25 KB

Box<[T]> に対する IntoIterator の追加

概要

  • ボックス化されたスライスは、すべてのエディションで IntoIterator を実装します。
  • 2024年以前のエディションでは、メソッド呼び出し構文(例: boxed_slice.into_iter() )で IntoIterator::into_iter への呼び出しが隠蔽されるため、これまでどおり boxed_slice.into_iter()(&(*boxed_slice)).into_iter() として解釈されます。
  • Rust 2024 では、boxed_slice.into_iter() の意味が IntoIterator::into_iter を呼び出すものに変わります。

詳細

Rust 1.80 以前は、ボックス化されたスライスに対して IntoIterator が実装されていませんでした。以前のバージョンでは、ボックス化されたスライスに対して .into_iter() を呼び出すと、メソッド呼び出しが自動的に Box<[T]> から &[T] への参照外しを行い、&T の参照を返すイテレータが生成されました。たとえば、以下のコードは以前のエディションで動作していました:

// 以前のエディションでの動作例
let my_boxed_slice: Box<[u32]> = vec![1, 2, 3].into_boxed_slice();
// 注意:1.80以前のバージョンでは .into_iter() の呼び出しが必要です
for x in my_boxed_slice.into_iter() {
    // Rust 2024 以前のエディションでは、x の型は &u32 です
}

Rust 1.80 では、ボックス化されたスライスに対して IntoIterator の実装が追加されました。これにより、スライスの要素を参照ではなく値としてイテレートできるようになります:

// 1.80以降、すべてのエディションでの新しい動作
let my_boxed_slice: Box<[u32]> = vec![1, 2, 3].into_boxed_slice();
for x in my_boxed_slice { // .into_iter() の呼び出しは不要になっています
    // x の型は u32 です
}

この例は、すべてのエディションで許可されています。というのも、以前は for ループが .into_iter() のように自動的に参照外しを行わなかったため、そもそもエラーになっていたからです。

しかし、本来であれば、これは破壊的変更となる可能性があります。なぜなら、これまで .into_iter() を明示的に呼び出していたコードの動作が、参照を返すイテレータから値を返すイテレータへと変わってしまうからです。この問題を解決するために、ボックス化されたスライスの .into_iter() の動作はエディションによって異なります。2024年以前のエディションでは、これまでどおり参照を返すイテレータを生成します。Rust 2024 以降では、値を返すイテレータを生成します。

// Edition 2024 での動作変更の例
let my_boxed_slice: Box<[u32]> = vec![1, 2, 3].into_boxed_slice();
// Example of old code that still manually calls .into_iter()
// .into_iter() を明示的に呼び出していた古いコードの例
for x in my_boxed_slice.into_iter() {
    // Edition 2024 では、x の型は u32 になります
}

移行

boxed_slice_into_iter リントは、ボックス化されたスライスに対する .into_iter() の呼び出しを .iter() に自動で置き換え、従来どおり参照を返すように修正します。このリントは rust-2024-compatibility リントグループの一部であり、cargo fix --edition を実行すると自動的に適用されます。Rust 2024 エディションに対応するために、次のコマンドを実行してください。

cargo fix --edition

例えば、以下のコードは:

fn main() {
    let my_boxed_slice: Box<[u32]> = vec![1, 2, 3].into_boxed_slice();
    for x in my_boxed_slice.into_iter() {
        // x の型は &u32
    }
}

次のように修正されます:

fn main() {
    let my_boxed_slice: Box<[u32]> = vec![1, 2, 3].into_boxed_slice();
    for x in my_boxed_slice.iter() {
        // x の型は &u32
    }
}

boxed_slice_into_iter リントはすべてのエディションでデフォルトで警告を出す設定になっているため、手動でリントを無効化していなければ、移行前にすでに警告が表示されるはずです。