プログラミングにおける借用とは?|借用とは何か、具体例をまじえながら3分わかりやすく解説

用語解説

こんちには。キノコードです。
このレッスンでは、 借用について説明をします。

▼ YouTube動画はこちらからどうぞ。

この記事の執筆・監修

キノコード
キノコード    

テクノロジーアンドデザインカンパニー株式会社のCEO。
日本最大級のプログラミング教育のYouTubeチャンネル「キノコード」や、プログラミング学習サービス「キノクエスト」を運営。
著書「あなたの仕事が一瞬で片付くPythonによる自動化仕事術」や、雑誌「日経ソフトウエア」や「シェルスクリプトマガジン」への寄稿など実績多数。

イミュータブル・ミュータブルとは?

例えば、プログラミング言語のRustでは、メモリ管理について、所有権・借用・ライフタイムという独特な仕組みを採用しています。
そのため、開発する上で制約の多いOSやコンパイラなどのソフトウェアを開発することができますし、高速に動くプログラムを書くことができます。
この独特なメモリ管理の借用について説明します。
まず、借用の前に、変数におけるイミュータブル、ミュータブルについて説明します。
イミュータブルな変数は、変数を作ったあとに、変数の中身を変更できません。
逆にミュータブルな変数は、あとから変数の中身を変更できます。
これを前提知識に借用の説明をします。

借用とは

借用とは所有権を移さず、変数の中身を一定期間だけレンタルすることです。
借用は3つのルールがあります。
1つ目は、イミュータブルな借用なら複数できること。
2つ目は、ミュータブルな借用なら1つしかできないこと。
3つ目は、イミュータブルな借用とミュータブルな借用は同時にできないことです。
コードを書きながらみていきましょう。

イミュータブルな複数の借用とは

借用とは所有権を移さず、変数の中身を一定期間だけレンタルすることです。

Rustでは、イミュータブルな借用なら複数できます。つまり、変更不可な借用は何個でも作れます。
RustとJavaのコードを比較して、借用の特徴を見ていきましょう。
まずJavaのコードを書いてみます。

-Java-

public static void main(String[] args) {

    String a = new String(""hello"");

    String b = a;

    System.out.println(a);

    System.out.println(b);

}

このところで、変数bに変数aを代入しています。
コンパイルして実行してみましょう。

hello

hello

aにもbにも「hello」が入っているので、helloが2つ表示されました。

次に、Rustのコードを書いてみましょう。

main(){

    let a = "hello".to_string();

    let b = a; //★

    println!("{}", a);

    println!("{}", b);

所有権の動画で説明しましたが、何もしなければエラーになります。

error[E0382]: borrow of moved value: a"

イミュータブル(変更不可)な借用は変数の前に & を付けます。

fn main(){

    let a = "hello".to_string();

    let b = &a;

    println!("{}", a);

    println!("{}", b);

}

コンパイルして実行します。

hello

hello

helloが2つ表示されました。

所有権のムーブではなく、借用であればエラーになりません。
なぜなら、変数aに所有権が残っているからです。
これでJavaと同じ書き方ができました。

ミュータブルな1つだけの借用とは

ミュータブルな1つだけの借用をみていきましょう。

Rustの前に、Javaの場合をみてみましょう。
Javaの場合は、ミュータブルな借用は複数できます。

配列yと配列zを作成しています。
これらは両方ミュータブルな参照です。

-Java-

public static void main(String[] args) {

    int[] x = new int[3];

    int[] y = x; int[] z = x;

    for (int i = 0; i < 3; i++) {

        y[i] = i + 1;

       z[i] = i * 2;

    }

    for (int val : x) {

        System.out.print(val + " ");

    }

}

コンパイルして実行してみましょう。

0 2 4

yで変更した内容が、zの内容で上書きされてしまいました。
一方、Rustの場合は、ミュータブルな借用は、複数することができません。
コードを書いて試してみましょう。

fn main(){

    let mut x = vec![0, 0, 0];

    let y = &mut x;

    let z = &mut x;

    for i in 0..3 {

        y[i] = i + 1;

        z[i] = i * 2;

    }

    for var in x {

        print!("{}", var);

        print!("{}", " ");

    }

}

ミュータブルな借用の場合、変数の前に &そのあとにmut をつけます。

実行してみましょう。

cannot borrow x as mutable more than once at a time

(直訳:一度に複数回「x」を可変として借りることはできません。) 

Rustだと、ミュータブルな借用を複数作ろうとするとエラーになります。
一方、ミュータブルな借用を1つだけしてみます。

fn main(){

    let mut x = vec![0, 0, 0];

    let z = &mut x;

    for i in 0..3 {

        z[i] = i * 2;

    }

    for var in x {

        print!("{}", var);

        print!("{}", " ");

    }

} 

エラーにならずxの配列を表示させることができました。
Rustには、このような厳格なルールがあることので、Javaのような、あとからzでデータを上書きしてしまうような問題が起こりません。
最後のルールの「借用は同時にできない」のルールをみていきましょう。

このコードはyがミュータブルな借用、zがイミュータブルな借用をしようとしています。
コンパイルして実行してみます。

fn main(){

    let mut x = vec![0, 0, 0];

    let y = &mut x;

    let z = &x;

    for i in 0..3 {

        y[i] = i + 1;

    }

    for var in x {

        print!("{}", var);

        print!("{}", " ");

    }

エラーとなります。
エラーを訳すと、「xは可変としても借りられているので、不変として借りることができません」という意味です。
これが、ミュータブルな借用と、イミュータブルな借用は同時にできないというルールです。

KinoCode チャンネル

YouTubeで毎日動画配信しています。
動画は3分間なので、
 ・通勤時間
 ・お昼休み
 ・お手すきのとき
 ・寝る前
など手軽に視聴できます。
 
ちょっとしたインプットにどうぞ!
 
▼チャンネル登録はこちらからどうぞ。
未経験からはじめるPython学習「キノクエスト」 キノクエスト
  • スキルアップしたいけど何からはじめればよいかわからない…
  • プログラミングスクールに入りたいけど料金が高い…
  • プログラミングを学んでも業務やキャリアに活かせるか不安…

キノクエストは、このような悩みを持つ方にぴったりのプログラミング学習サービスです。
国内最大級のプログラミング学習系YouTubeチャンネル「キノコード」が提供しているから、未経験者にもわかりやすく質の高い学習体験を実感していただけます。

キノクエスト