グローバルナビゲーションへ

本文へ

フッターへ

お役立ち情報Blog



安全性、速度、並行性を兼ね備えた言語と、巷でうわさの「Rust」を覗いてみる(その2:変数)

前回の記事「安全性、速度、並行性を兼ね備えた言語と、巷でうわさの「Rust」を覗いてみる(その1)」に続き、今回は「The Rust Programming Language」を読みながら、変数の部分を覗いていきたいと思います。

変数は基本的にイミュータブル

まずは、文字列を出力する単純なコードを書きます。

fn main() {
    let name = "foo";

    println!("{}", name);
}
 println! の最後の「!」はマクロを表し、第一引数の「{}」はプレースホルダらしいです。

Rustは、明示的に「mut」をつけないと再代入不可能とのことなので、

fn main() {
    let name = "foo";
    println!("{}", name);

    name = "bar";
    println!("{}", name);
}

むりやりnameに再代入してコンパイルすると・・・。

$ cargo run
   Compiling hello-rust v0.1.0 (/home/*****/github.com/*****/hello-rust)
error[E0384]: cannot assign twice to immutable variable `name`
 --> src/main.rs:5:5
  |
2 |     let name = "foo";
  |         ----
  |         |
  |         first assignment to `name`
  |         help: consider making this binding mutable: `mut name`
...
5 |     name = "bar";
  |     ^^^^^^^^^^^^ cannot assign twice to immutable variable

For more information about this error, try `rustc --explain E0384`.

想定通り怒られます。

変数をミュータブルにする

 mut をつけて変更可能にしてみます。

fn main() {
    let mut name = "foo";
    println!("{}", name); // foo

    name = "bar";
    println!("{}", name); // bar
}

nameに再代入できるようになりました。

note: mutをいつ使うのか

考えるべきトレードオフはバグの予防以外にも、いくつかあります。例えば、大きなデータ構造を使う場合などです。 インスタンスを可変にして変更できるようにする方が、いちいちインスタンスをコピーして新しくメモリ割り当てされたインスタンスを返すよりも速くなります。 小規模なデータ構造なら、新規インスタンスを生成して、もっと関数型っぽいコードを書く方が通して考えやすくなるため、 低パフォーマンスは、その簡潔性を得るのに足りうるペナルティになるかもしれません。The Rust Programming Language 日本語版

このように書かれています。

基本的にはmutを付けずに関数型プログラミングスタイルで記述し、 パフォーマンスが気になる箇所はmutを付ける運用にするのが良さそうです。

シャドーイング

 mut は、変数を可変にしますが、シャドーイングは変数を新しく生成して上書きします。

fn main() {
    let name = "foo";
    println!("{}", name); // foo

    let name = "bar";
    println!("{}", name); // bar
}
fn main() {
    let name = "foo";
    println!("{}", name); // foo

    let name = 1;
    println!("{}", name); // 1
}

シャドーイングするときは、一つ目と違う型にできます。 書き味が良さそうだなと思う反面、同名の変数でも型が異なる事があるので、 長く複雑なコードを書くと保守が大変そうです。

ブロックとスコープと凍結(Freezing)

最後に、ブロックとスコープを確認します。

fn main() {
    let name = "foo";
    println!("{}", name); // foo

    {
        println!("{}", name); // foo

        let name = 1;
        println!("{}", name); // 1
    }

    println!("{}", name); // foo
}

ブロック内でシャドーイングしていますが、ブロックを抜けると元の値にもどってることが確認できます。

これらを使って、 mut の変数をブロック内で変更不能にしてみます。

fn main() {
    let mut name = "foo";
    {
        let name = name;

        name = "bar"; // error
    }
}

ブロックの中で mut の変数を mut 無しでシャドーイングすることで、 そのスコープ内で変数を凍結(Freezing)できます。

この記事を書いた人

tkr2f
tkr2f事業開発部 web application engineer
2008年にアーティスへ入社。
システムエンジニアとして、SI案件のシステム開発に携わる。
その後、事業開発部の立ち上げから自社サービスの開発、保守をメインに従事。
ドメイン駆動設計(DDD)を中心にドメインを重視しながら、保守可能なソフトウェア開発を探求している。
この記事のカテゴリ

FOLLOW US

最新の情報をお届けします