Rust

出典: フリー教科書『ウィキブックス(Wikibooks)』
ナビゲーションに移動 検索に移動
Wikipedia
ウィキペディアRustの記事があります。
メインページ > 工学 > 情報技術 > プログラミング > Rust

Rust(ラスト)は、Rustは、性能と安全性、特に安全な並行実行を目指して設計されたマルチパラダイム汎用プログラミング言語です[1]

Rustは構文はC++に似ているが、ボローチェッカーを使って参照を検証することでメモリ安全性を保証することができます。 Rustはガベージコレクター()を使わずにメモリ安全性を実現しており、オプションでリファレンスカウントによる管理も可能です。 Rustはシステムプログラミング言語と呼ばれており、関数型プログラミングのような高レベルの機能に加えて、低レベルのメモリ管理のメカニズムも提供しています。

Hello World[編集]

Rustで Hello World を書くと、

hello.rs
fn main() {
    println!("Hello, world!");
}
実行結果
Hello, world!

hello.rsは、Playgroundに作った、このプログラムへのリンクになっています。

コメント[編集]

Rustのコメントには、C言語/C++と同じく一行コメントと範囲コメントがあります。

一行コメント
//から行末までがコメントと見なされます。
範囲コメント
/*から*/までがコメントと見なされます。
ネストは許されません。
コメントの例
/*
 * プログラムのエントリーポイントは、main 関数です。
 * 関数定義は fn から始まります。
 */
fn main() {
    println!("Hello, world!"); // println! は関数ではなくマクロで、マクロは識別子の末尾に ! が付きます。
}

変数と型[編集]

Rustは、静的な型システムを採用しています。

variables-types.rs
fn main() {
    let x = 999;
    print!("{}({}), ", x, type_of(x));
    let x = -123;
    print!("{}({}), ", x, type_of(x));
    let x = 999u32;
    print!("{}({}), ", x, type_of(x));
    let x = -123i32;
    print!("{}({}), ", x, type_of(x));
    let x = 999u64;
    print!("{}({}), ", x, type_of(x));
    let x = -123i64;
    print!("{}({}), ", x, type_of(x));
    let x = 1.0;
    print!("{}({}), ", x, type_of(x));
    let x = 3.14f32;
    print!("{}({}), ", x, type_of(x));
    println!();
    let x = "abc";
    print!("{}({}), ", x, type_of(x));
    let x = true;
    print!("{:?}({}), ", x, type_of(x));
    let x = [1, 2, 3];
    print!("{:?}({}), ", x, type_of(x));
    let x = (1, 2, 3);
    print!("{:?}({}), ", x, type_of(x));
    let x = &vec![10, 20, 30];
    print!("{:?}({}), ", x, type_of(x));
}

fn type_of<T>(_: T) -> &'static str {
    std::any::type_name::<T>()
}
実行結果
999(i32), -123(i32), 999(u32), -123(i32), 999(u64), -123(i64), 1(f64), 3.14(f32), 
abc(&str), true(bool), [1, 2, 3]([i32; 3]), (1, 2, 3)((i32, i32, i32)), [10, 20, 30](&alloc::vec::Vec<i32>),

変数・定数とミュータブル・イミュータブル[編集]

Rustでは、変数を宣言するにはletを使いますが、ディフォルトでつ売られるのはイミュータブル(Immutable;作成後には変更不能)な変数です。 ミュータブル(Mutable;作成後にも変更可能)な変数を宣言するには、追加のキーワード mut を使います。

hello-variables.rs
fn main() {
    let hello : &str = "Hello, world!"; 
    println!("{}", hello);
}
実行結果
Hello, world!
2行目のlet hello : &str = "Hello, world!";が変数宣言です[2]
文字列のスライスのリファレンスである変数 hello を宣言し、"Hello, world!"で初期化しています。

型推論[編集]

Rust では、変数宣言が初期値を伴っていた場合、変数の型を省略することができ、その場合変数の型は初期値の型になります。

hello-type-inference.rs
fn main() {
    let hello = "Hello, world!"; 
    println!("{}", hello);
}
実行結果
上に同じ

イミュータブル[編集]

Rust では、単に let で宣言された変数は

hello-immutable.rs
fn main() {
    let hello : &str = "Hello, world!"; 
    println!("{}", hello);
    hello = "Hello, rust!";
    println!("{}", hello);
}
コンパイル結果
error[E0384]: cannot assign twice to immutable variable `hello`
 --> src/main.rs:4:5
  |
2 |     let hello : &str = "Hello, world!"; 
  |         -----
  |         |
  |         first assignment to `hello`
  |         help: consider making this binding mutable: `mut hello`
3 |     println!("{}", hello);
4 |     hello = "Hello, rust!";
  |     ^^^^^^^^^^^^^^^^^^^^^^ cannot assign twice to immutable variable

For more information about this error, try `rustc --explain E0384`. 
error: could not compile `playground` due to previous error
イミュータブルな変数には、再代入できないというコンパイルエラーです。

ミュータブル[編集]

ミュータブルな変数を宣言するには let と併せてキーワード mut を使います。

hello-mutable.rs
fn main() {
    let mut hello : &str = "Hello, world!"; 
    println!("{}", hello);
    hello = "Hello, rust!";
    println!("{}", hello);
}
実行結果
Hello, world! 
Hello, rust!

パターン[編集]

pattern.rs
fn main() {
    let (mut x, mut y) = (5, 29);
    println!("x={} Y={}", x, y);
    let (p, q) = (x, y);
    x = q;
    y = p;
    println!("x={} Y={}", x, y);
}
実行結果
x=5 Y=29
x=29 Y=5

データー型[編集]

Restには豊富なデーター型(Data Types)があり、それらを組み合わせて新しい型を作ることができます[3]

スカラー型(Scalar Types)[編集]

スカラー型は単一の値を表します。Rustには、整数、浮動小数点数、論理値、文字という4つの主要なスカラ型があります。

整数型(Integer Types)[編集]

Rustの整数型は、符号の有無とビット幅から12種類のバリエーションがあります。

i8
符号付き8ビット整数
u8
符号なし8ビット整数
i16
符号付き16ビット整数
u16
符号なし16ビット整数
i32
符号付き32ビット整数
u32
符号なし32ビット整数
i64
符号付き64ビット整数
u64
符号なし64ビット整数
i128
符号付き128ビット整数
u128
符号なし128ビット整数
isize
符号付きでアーキテクチャーに自然な整数
usize
符号なしでアーキテクチャーに自然な整数
isizeとusizeのビット幅はプロセッサーのアーキテクチャーによって定義され、32ビットプロセッサーならば32、64ビットプロセッサーならば64です。
整数リテラル(Integer literals)[編集]

リテラル(Literals)とは、プログラミングのソースコードで使用される、数値や文字列などのデーターを直接表現したものです。

様々な整数リテラル
基数 表現
10 19_800
16 0xbadbeef
8 0o777
2 0b101_111_011
バイト(u8のみ) b'Q'
fn main() {
    println!("{:?}", 19_800);
    println!("{:x}", 0xbadbeef);
    println!("{:o}", 0o777);
    println!("{:b}", 0b101_111_011);
    println!("{}", b'Q');
}
実行結果
19800
badbeef
777
101111011
81

数値リテラルには、123u8 の様に型名をタイプサーフィックス(type suffix)として補うことで、ビット幅を明記できます(オプショナル)。
指定されない場合は(バイト以外は)i32が仮定されます(isizeではありません)。
数値リテラルには、読みやすさのため 9_281_636 のように、アンダースコア _ を補うことができます(オプショナル)。
浮動小数点数型(Floating-Point Types)[編集]

Rustの浮動小数点数型には、f64 と f32 があり、サイズを明示しないと f64 になります。 浮動小数点数は、IEEE-754規格に従います。

論理値型(The Boolean Type)[編集]

Rustの論理値型の型名は bool、真の値は true 偽の値は false です。

文字型(The Character Type)[編集]

Rustの文字型の型名は char です。 char は Unicode のサロゲートペアであっても保持できます。

文字列型(The String Type)[編集]
string.rs
fn main() {
    println!("{:?}", "hello");     // エスケープされた文字列
    println!("{:?}", r#"hello"#);  // エスケープされないraw文字列
    println!("{:?}", b"hello");    // エスケープされたバイト文字列
    println!("{:?}", br#"hello"#); // エスケープされないrawバイト文字列
}
実行結果
"hello"
"hello"
[104, 101, 108, 108, 111]
[104, 101, 108, 108, 111]

複合型(Compound Types)[編集]

複合型(Compound Types)は、複数の値を1つの型にまとめることができます。 Rustにはタプルとアレイという2つのプリミティブな複合型があります。

タプル型(The Tuple Type)[編集]

タプル(The Tuple')は、さまざまな型の値を1つの複合型にまとめる一般的な方法です。 タプルの長さは固定されており、一度宣言すると大きくしたり小さくしたりすることはできません。

配列型(The Array Type)[編集]

複数の値の集まりを持つもう一つの方法として、配列(The Array)があります。 タプルとは異なり、配列の各要素は同じ型でなければなりません。 Rustの配列は、タプルと同じく長さが固定されています。

ムーブセマンティクスとコピーセマンティクス[編集]

識別子[編集]

スコープ[編集]

制御構造[編集]

Rust では、ifforなどの制御構造も式です。

分岐[編集]

if.rs
fn main() {
    let number = 3;

    if number < 5 {
        println!("条件は真でした");
    } else {
        println!("条件は偽でした");
    }
    println!(
        "条件は{}でした",
        "偽真".chars().nth((number < 5) as usize).unwrap()
    );
}
実行結果
条件は真でした
条件は真でした
C言語なら"偽真"[number < 5]で済むところですが、str はインデックスによるアクセスができず、boolは暗黙にはusizeに変換されないので、こうなりました。
それはともかく、Rust の if は条件式がカッコ ( ) で括らなくてもいい以外は、C言語系と同じですが、、、

if は式[編集]

if-as-expr.rs
fn main() {
    let number = 3;

    let msg = if number < 5 {
        "真"
    } else {
        "偽"
    };
    println!("条件は{}でした", msg);
}
実行結果
条件は真でした
変数宣言の初期化項にif式を使っています。
Rustの if は、C言語の三項演算子のように値を持ちます。
気をつけたいのは、"真""偽" は、"真";"偽"; ではない点です。
また、let msg =の文末の}; のセミコロンも忘れがちです。

Some()[編集]

https://doc.rust-lang.org/stable/std/option/enum.Option.html

some.rs
fn main() {
    let mut x = Some(0);
    println!("{:?}({})", x, type_of(x));
    x = None;
    println!("{:?}({})", x, type_of(x));
}

fn type_of<T>(_: T) -> &'static str {
    std::any::type_name::<T>()
}
実行結果
Some(0)(core::option::Option<i32>)
None(core::option::Option<i32>)

if let[編集]

if-let.rs
fn main() {
    let mut v = vec![2, 3, 5];

    if let Some(x) = v.pop() {
        println!("x = {}", x)
    } else {
        println!("done!")
    }
    if let Some(x) = v.pop() {
        println!("x = {}", x)
    } else {
        println!("done!")
    }
    if let Some(x) = v.pop() {
        println!("x = {}", x)
    } else {
        println!("done!")
    }
    if let Some(x) = v.pop() {
        println!("x = {}", x)
    } else {
        println!("done!")
    }
    if let Some(x) = v.pop() {
        println!("x = {}", x)
    } else {
        println!("done!")
    }
}
実行結果
x = 5
x = 3
x = 2
done!
done!

反復[編集]

loop と break の値[編集]

Rest には、永久ループのためのキーワード loop が用意されています。

loop-and-break.rs
fn main() {
    let mut i = 0;
    let result = loop {
        if i > 3 {
            break 100;
        }
        println!("i = {}", i);
        i += 1;
    };
    println!("result = {}", result);
}
実行結果
i = 0
i = 1
i = 2
i = 3
result = 100
loopも値を返せる式です。
と言ってもloop自体は無限ループなので、break文のオペランドが値になります。

continue[編集]

ループのフローコントロール文にもう一つ continue があります。

continue.rs
fn main() {
    let mut i = 0;
    let result = loop {
        if i > 10 {
            break 100;
        }
        if i % 2 == 0 {
            i += 1;
            continue;
        }
        println!("i = {}", i);
        i += 1;
    };
    println!("result = {}", result);
}
実行結果
i = 1
i = 3
i = 5
i = 7
i = 9
result = 100
continue は、ループの先頭に戻ります。

while[編集]

Rust には、条件が成立するあいだ反復するためのキーワード while が用意されています。

while.rs
fn main() {
    let mut i = 0;
    while i < 5 {
        println!("i = {}", i);
        i += 1
    };
}
実行結果
i = 0
i = 1
i = 2
i = 3
i = 4
while let[編集]
while-let.rs
fn main() {
    let mut n = Some(0);
    while let Some(i) = n {
        n = if i > 5 {
            None
        } else {
            println!("i = {}", i);
            Some(i + 1)
        }
    }
}
実行結果
i = 0
i = 1
i = 2
i = 3
i = 4
i = 5
while let again[編集]
while-let-again.rs
fn main() {
    let mut v = vec![1, 3, 5, 7, 11];
    while let Some(x) = v.pop() {
        println!("x = {}", x)
    }
}
実行結果
x = 11
x = 7
x = 5
x = 3
x = 1
Rustにdo-whileはありません
Rustにdo-whileはありません。while の条件式に do のブロックを詰め込むことで同じことが実現できます。
pseudo-do-while.rs
fn main() {
    let mut i = 100;
    while {
        println!("{}", i);
        i += 1;
        i < 10
    } {}
}
実行結果
100
whileの条件式が省略されたかのように見えますが、4,5,6行目を含むブロックが、while の条件式となり値はブロックの最後の6行目の式の値です。
7行目の {} がループ本体です。


for[編集]

Rust の for は、他のプログラミング言語の foreach に近いものです。

Range[編集]
for-in-range.rs
fn main() {
    for i in 1..5 {
        println!("i = {}", i);
    }
}
実行結果
i = 1
i = 2
i = 3
i = 4
std::ops::Range<{integer}>を対象にしたイテレーション。
Range[編集]
for-in-range2.rs
fn main() {
    for i in 1..=5 {
        println!("i = {}", i);
    }
}
実行結果
i = 1
i = 2
i = 3
i = 4
i = 5
=5だけが違います。範囲の最後の数字が異なります。
Iter[編集]
iter.rs
fn main() {
    let v = vec![1, 3, 5, 7, 11];
    for x in v {
        println!("x = {}", x)
    }
}
実行結果
x = 1
x = 3
x = 5
x = 7
x = 11
std::ops::Range<{integer}>を対象にしたイテレーション。
Iter Rev[編集]
iter-rev.rs
fn main() {
    let v = vec![1, 3, 5, 7, 11];
    for x in v.iter().rev() {
        println!("x = {}", x)
    }
}
実行結果
x = 11
x = 7
x = 5
x = 3
x = 1
std::ops::Range<{integer}>を対象にしたイテレーション。

脚註[編集]

  1. ^ Hoare, Graydon (2016年12月28日). “Rust is mostly safety”. Graydon2. Dreamwidth Studios. 2021年12月3日閲覧。
  2. ^ 文字リテラルであることを強調するならlet hello : &'static str = "Hello, world!";とすべきだったかもしれません。
  3. ^ Data Types - The Rust Programming Language”. 2021年12月8日閲覧。

外部リンク[編集]

参考文献[編集]

  • Jim Blandy, Jason Orendorff: 「プログラミングRust」、オライリージャパン 、ISBN 978-4873118550 (2018年8月10日)。