Open4

Rustの参照・借用のお話

プリミティブ型に関しては、代入しても所有権が移動しない

fn main() {
    let num = 1_usize;
    let tmp_num = num;

    println!("{}", num);
    println!("{}", tmp_num);
}

nums にあった所有権が tmp_nums へ移動してしまったので
以下のソースコードはコンパイルエラー になってしまう。

fn main() {
    let nums = vec![1, 2, 3];
    // 所有権がtmp_numsへ移動
    let tmp_nums = nums;

    // コンパイルエラー
    println!("{:?}", nums);
}

借用という仕組みで解決する。
& を用い、値そのものを渡すのではなく、
参照をわたすことでコンパイルエラー を解決することができます。

fn main() {
    let nums = vec![1, 2, 3];
    // 借用
    let tmp_nums = &nums;

    println!("{:?}", nums);
    println!("{:?}", tmp_nums);
}

もちろん関数に値を渡す場合も、所有権の移動は発生する。
以下のプログラムもコンパイルエラーを起こす。

fn main() {
    let nums = vec![1, 2, 3];
    // 所有権が移動
    let plus_one_nums = plus_one(nums);

    // コンパイルエラー
    println!("{:?}", nums);
}

fn plus_one(nums: Vec<usize>) -> Vec<usize> {
    nums.iter().map(|v| v + 1).collect()
}

引数に&をつけることで、借用を用い
コンパイルエラーを解決することができる。

fn main() {
    let nums = vec![1, 2, 3];
    let plus_one_nums = plus_one(&nums);

    // [1, 2, 3]
    println!("{:?}", nums);
    // [2, 3, 4]
    println!("{:?}", plus_one_nums);
}

fn plus_one(nums: &Vec<usize>) -> Vec<usize> {
    nums.iter().map(|v| v + 1).collect()
}

参照はポインタとは違うので参照を変更しようとするとコンパイルエラー が起こる。

fn main() {
    let nums = vec![1, 2, 3];
    change_nums(&nums);

    println!("{:?}", nums);
}

fn change_nums(nums: &Vec<usize>) {
    // コンパイルエラー
    nums[0] = 999
}

こちらを解決するには、
可変参照と言われる&mutというキーワードを使用する。

fn main() {
    let mut nums = vec![1, 2, 3];
    change_nums(&mut nums);

    // [999, 2, 3]
    println!("{:?}", nums);
}

fn change_nums(nums: &mut Vec<usize>) {
    nums[0] = 999
}
ログインするとコメントできます