Keyboard shortcuts

Press or to navigate between chapters

Press ? to show this help

Press Esc to hide this help

Vecとスライス

計算物理では、時系列データ、粒子の状態、格子上の場など、多数の数値をまとめて扱います。1次元の数値データでは、まずVec<f64>とsliceを使えることが重要です。

所有するデータとしてのVec<f64>

Vec<f64>は、実行時に長さが決まる数値列を所有します。例えば、時刻ごとのエネルギーを保存する場合は次のように使います。

let mut energy: Vec<f64> = Vec::with_capacity(1000);

for step in 0..1000 {
    let e = step as f64 * 0.01;
    energy.push(e);
}

要素数の上限が分かっている場合は、Vec::with_capacityで容量を確保しておくと、途中の再割り当てを減らせます。

関数境界としての&[f64]

関数に数値列を渡すときは、多くの場合Vec<f64>そのものではなく&[f64]を受け取ります。

fn mean(xs: &[f64]) -> Option<f64> {
    if xs.is_empty() {
        return None;
    }

    let sum: f64 = xs.iter().sum();
    Some(sum / xs.len() as f64)
}

&[f64]はデータを所有しません。配列、Vec<f64>、配列の一部などを同じ関数に渡せます。

let xs = vec![1.0, 2.0, 3.0];
let avg = mean(&xs);
let first_two = mean(&xs[0..2]);

更新を伴う関数境界としての&mut [f64]

データをその場で更新する関数では、&mut [f64]を使います。

fn scale(xs: &mut [f64], factor: f64) {
    for x in xs {
        *x *= factor;
    }
}

let mut xs = vec![1.0, 2.0, 3.0];
scale(&mut xs, 0.5);

可変にする範囲を関数境界で明示することで、どのデータが変更されうるかを読み取りやすくなります。これはAI agent が生成した差分をレビューするときにも役立ちます。

stack、heap、所有権

小さな固定長配列、例えば3次元ベクトル[f64; 3]は値そのものとして扱いやすいデータです。一方、Vec<f64>は、長さが実行時に決まるデータをheap上に持ちます。

数値計算コードでは、次の使い分けを基本にします。

  • 小さく固定長の量: [f64; 2], [f64; 3]
  • 実行時に長さが決まる1次元データ: Vec<f64>
  • 関数の入力: &[f64]
  • 関数内で更新する入力: &mut [f64]

所有権や借用は、最初は複雑に見えるかもしれません。しかし、数値計算では「どの関数がデータを所有するか」「どの関数が読むだけか」「どの関数が更新するか」をはっきりさせる仕組みとして有用です。

Last change: , commit: 23d4376