読者です 読者をやめる 読者になる 読者になる

(-> % read write unlearn)

All opinions expressed are solely my own and do not express the views or opinions of my employer.

rust-lang#03 Primitive Types & Comments

rust

前回の Variable Bindings と Functionsに続いてhttps://doc.rust-lang.org/bookをやっていきます。

今日は4.3. Primitive Typesからです。

4.3. Primitive Types

Primitive Types

primitiveな型は全て、Rust言語に組み込みの型です。 構成はJavaなどの他の言語と似ています。char型がUnicodeの4byteというのが、思い切ってるというか新しい言語ならではだな、と感じました。

Booleans

boolは真偽値の型です。truefalseどちらかの値を持ちます。

fn main() {
    let x = true;         // 型注釈なしだと型推論される
    let y: bool = false;  // 型注釈あり

    if x {
        println!("x={}, y={}", x, y);
    }
    //=> x=true, y=false
}

char

  • char型は、ユニコードスカラ値です。
  • シングルクォート(')で囲んで表記します。
  • Rustのchar型は、1byteではなく4byteです。 他の言語と違うところです。
// ASCIIはもちろん、
let x = 'x';

// ユニコードなので絵文字もいけるよ!
let two_hearts = '💕';

Numeric types

Rustにはたくさんの数値型があります。

数値型の型名は次のような構成になっています。

  • 最初の1文字が分類。
  • 2文字目以降がサイズ。

例えば、i32型なら、32bit符号付き整数を指します。

8bit 16bit 32bit 64bit 可変長
符号付き整数 (integer) i8 i16 i32 i64 isize
符号無し整数 (unsigned integer) u8 u16 u32 u64 usize
浮動小数点 (float) - - f32 f64 -

Javaにはprimitiveな符号無し数値型は存在しないですよね。 あれば便利そうだけど。 C#の整数型の一覧MySQLの整数型には、符号無しの数値型があります。 近いですね。

Signed and Unsigned

型名の1文字目は、符号付きか符号無しかを表しています。 例えば、
i8型は-128127の範囲を表現し、
u8型は0255の範囲を表現します。

Fixed-size types

型名の2文字目以降が数字になっている数値型は、固定長の数値型です。 例えばi64なんかは64bit固定長です。

Variable-size types

可変長の数値型も2つ存在します。
isizeusizeです。

Floating-point types

f32f64IEEE-754準拠の単精度と倍精度の浮動小数点数です。

Arrays

  • 配列型は、同種の型の要素からなる固定長のリストです。
  • 配列型はデフォルトではイミュータブルです。
  • ミュータブルにするにはやはりletを使います。
  • 配列の型注釈は[T; N]のように表記します。
    • Tは、要素の型を表現するジェネリクスのようですが、単に型を記述しても大丈夫です。
    • Nは、配列の長さです。コンパイル時のチェックに使用されます。
fn main() {
    // 型推論により a1: [i32; 3] つまり「i32型の要素が3つ」という型になる。
    let a1 = [10, 20, 30];

    // mutを使えばミュータブルになるのは変わらず。
    let mut a2 = [10, 20, 30];

    // [i32; 100]型に推論され、全ての要素が 0 で初期化される
    let a3 = [0; 100];

    // サイズ取得の len() メソッド
    println!("a3.len()={}", a3.len());
    //=> a3.len()=100

    // 添字アクセス
    println!("The second number is: {}", a1[1]);
    //=> The second number is: 20

    // 範囲外に添字アクセス
    println!("The fourth number is: {}", a2[3]);
    //=> ランタイムエラー
}

最後のエラーは、ラインタイム時です。 コンパイル時にチェックされるわけではないようですね。

thread '<main>' panicked at 'index out of bounds: the len is 3 but the index is 3', src/main.rs:20
note: Run with `RUST_BACKTRACE=1` for a backtrace.
Process didn't exit successfully: `target/debug/foo` (exit code: 101)

Slices

  • sliceは別のデータ構造への参照(あるいはビュー)です。
  • sliceによって、例えば「ある文字列の最初の1行」のような、配列の特定の部分への効率的なアクセスが可能になります。
  • イミュータブルにもミュータブルにもできます。
  • 内部的には、該当のデータの始点のポインタその長さで表現されています。

str

  • Rustのstr型は、primitiveな文字列型です。
  • &strのような参照に隠されたかたちで利用されることが多いようです。

Tuples

  • タプルは、順序のある固定長のリストです。
  • タプルの型宣言はタプル表記と同様に()内にカンマ区切りで、要素の型を列挙します。
  • タプルは異種混合(heterogeneous)の型です。 つまり、異なる型を要素に保持できます。同種の型の要素を保持する配列とは異なります。
fn main() {
    // タプルを変数に束縛
    let x = (10, "hello");

    // 型注釈を明示することももちろん可能
    let y: (i32, &str) = x;

    // 要素を分配束縛するのにタプル表記が使える。
    let (one, two, three) = (10, "hello", 123);
    println!("{}, {}, {}", one, two, three);
    //=> 10, hello, 123

    // 要素が1つだけのタプルは、ケツカンマが必要
    let (z,) = (999,);
    println!("{}", z);
    //=> 999

    // これは、要素が1つのタプルとはみなされない。コンパイルエラーになる。
    // let (z) = (999);
}

Tuple Indexing

タプルも配列みたいに添字アクセスができるが、添字の記法が異なります。

fn main() {
    let t = (111, 222, "three");

    // タプルの添字アクセス
    println!("{}", t.0);
    //=> 111

    // 範囲外のアクセスはコンパイルエラー
    // println!("{}", t.3);
}

Functions

関数にも型があります。 例えば、「32bit符号付き整数を1つ受け取って、32bit符号付き整数を1つ返す関数」の型はfn(i32) -> i32です。

fn main() {
    fn increment(x: i32) -> i32 { x + 1 }

    let x = increment;
    println!("{}", x(100));
    //=> 101

    // もちろん型注釈を明示してもよい
    let y: fn(i32) -> i32 = increment;
    println!("{}", y(200));
    //=> 201
}

Comments

行コメントとdocコメントの2種類があります。

行コメントは//以降行末までです。

docコメントはマークダウン記法をサポートします。*1
また、2種類の記法があります。

/////!です。 //!は主にcrateのルート(lib.rs)やモジュールのルート(mod.rs)内で使用されるようです。

rustdocというツールでdocコメントからドキュメントを生成することができます。

*1:rustdocがdocコメント内のマークダウンをサポートするという意味なのではないかと思います。