Cwらぼっちゃ - IT技術研究ノート -

IT技術に関する記事を掲載します。

Rust言語

Rustとは

Rustは、Mozilaとコミュニティで開発されているオープンソースプログラミング言語です。C/C++の後継として目されています。 公式ドキュメントが英語だけでなく日本語もあるので、入門しやすいと思います。 おまけにブラウザ上でRustの実行が可能なサイトも載せていますので、是非お試しください。

特徴

  • C/C++に比べてメモリ周りがセキュア1
  • 静的型付け。

Cargo

RustはCargoと呼ばれるビルドシステム兼パッケージマネージャを使用します。プロジェクトのビルドや実行、依存関係にあるライブラリのダウンロード、ビルド等も可能です。ここでは簡単な説明だけしますので、詳しくは公式のドキュメントをご参照ください。

プロジェクトの作成

ターミナルで下記コマンドを実行すると、「hello_cargo」という名称のプロジェクトがカレントディレクトリの直下に作成されます。

cargo new hello_cargo --bin

実はこの時点でソースコードも生成され、実行可能な状態となっています。プロジェクトフォルダに移動してビルド、実行してみましょう。

cd hello_cargo
cargo run

実行すると、下記が出力されます。

Hello, world!

「hello_cargo/src/main.rs」ファイルが生成されているので、内容をみてみましょう。「Hello, world!」を出力するコードが書かれていることがわかると思います。基本的にはこの中身を編集することでプログラムを作成していくことになります。

fn main() {
    println!("Hello, world!");
}

記法

変数宣言

公式ドキュメントでは「変数束縛」という名称が用いられています。主に以下の要素で記法が変わります。

  • 可変性(mutable/immutable)
  • 型の明示的宣言
  • 初期化の有無
可変性

宣言の仕方によって変数の可変性が変わります。以下に例を示します。

let x = 10;         // 不可変
let mut y = 20;     // 可変

x = 30;             // コンパイルエラー
y = 40;

上記のように、mutをつけると可変、つけないと不可変となります。

型の明示的宣言

基本的な型(プリミティブ型)は明示的に宣言せずともコンパイルできます。型を明示的に宣言したいとき、構造体を使うとき等に使用することになるでしょう。

let x: i32;     // 符号付32bit整数
let y: u64;     // 符号無64bit整数

ちなみに下記のように初期化せず、型を明示的に宣言しない場合はコンパイルエラーとなります。

let x;      // コンパイルエラー

条件分岐

If文

通常は下記のように書きます。

let x = 5;
if x == 5 {
    println!("x は 5 です!");
} else if x == 6 {
    println!("x は 6 です!");
} else {
    println!("x は 5 でも 6 でもありません!");
}

そして、別の書き方として下記があります。簡単な条件分岐はこの書き方が推奨されているようです。xの値を条件にyの値を初期化する、という文です。

let x = 5;
let y = if x == 5 { 10 } else { 15 };

ループ

ループは3種類あります。

loop

単純な無限ループで使用します。

loop {
    println!("無限ループ!");
}
while

loopに条件がついたものです。逆にwhile trueがloopにあたります。

let mut x = 5;
let mut done = false;

while !done {
    x += x - 3;

    println!("{}", x);

    if x % 5 == 0 {
        done = true;
    }
}
for

初期化子、反復子で構成されます。Java等の他の言語でよくある条件部分がありません。

for x in 0..10 {
    println!("{}", x); // x: i32
}

ループ中で何回目の繰り返しかを知ることもできます。.enumerate()関数をつかいます。

for (i,j) in (5..10).enumerate() {
    println!("i = {} and j = {}", i, j);
}

iに0始まりの回数が入ります。出力は下記になります。

i = 0 and j = 5
i = 1 and j = 6
i = 2 and j = 7
i = 3 and j = 8
i = 4 and j = 9

上記ではレンジを対象にしていますが、イテレータを対象にした使い方もあります。興味があれば公式ドキュメントをご参照ください。

break

無限ループや条件に合致したときにループを抜けるための記法です。

let mut x = 5;

loop {
    x += x - 3;

    println!("{}", x);

    if x % 5 == 0 { break; }    // xが5の倍数のときにループを抜ける
}
continue

ループをスキップして、次のループに進めるための記法です。

for x in 0..10 {
    if x % 2 == 0 { continue; }    // 2の倍数(偶数)のときにスキップ

    println!("{}", x);
}

所有権

Rustには所有権(Ownership)という概念があります。変数束縛という名称にも関係してくる重要な概念なのですが、説明が難しいので省きます。C/C++のポインタぐらい重要な気がします。興味があれば公式ドキュメントをご参照ください。
https://doc.rust-jp.rs/the-rust-programming-language-ja/1.6/book/ownership.html

ベクタ

ベクタは拡張可能な配列です。インデックスにはusize型を使用する必要があります。

let v = vec![1, 2, 3, 4, 5];

let i: usize = 0;
let j: i32 = 0;

v[i];           // usizeなのでOK
v[j];           // usizeではないのでNG、コンパイルエラー

for文でイテレートに使用も可能です。

let mut v = vec![1, 2, 3, 4, 5];

for i in &v {
    println!("A reference to {}", i);
}

ここでベクタの変数vを反復子に指定するときの記法で意味が変わってきます。ここでは説明を省きます。

文字列

文字列は&strとStringの2種類あります。またいずれもUTF-8のシーケンスであることが保証されています。

&str
String
  • 可変長
  • 拡張可能

&strは.to_string()によってStringに変換され、またStringは&によって&strに型強制されます。C++のchar*とstd::stringみたいな関係になるでしょうか。ちなみにStringの.push_str()はStringの宣言時にmutをつけないとコンパイルエラーになります。

let a = "Hello";            // &'static str
println!("{}", a);

let mut b = a.to_string();  // &str -> String
b.push_str(", world!");     // 文字列追加
println!("{}", &b);         // String -> str

終わりに

前述の通りRustはC/C++の後継として注目されています。新しい概念や記法はありますが、書きやすいと思います。今後C/C++に代わる言語として使用されていくことになればどんどん普及していくことになると思います。この機会に是非触れてみてはいかがでしょうか?
ちなみに筆者はVSCodeで開発しています。開発環境構築は別途検索してみてください。

おまけ