百鬼夜行

素性を知られぬままエンジニアになることを目指します

「The Book」で Rust 入門 3 前半

前回のあらすじ

yagyosan.hatenablog.com

一般的なプログラミングの概念

一般的なプログラミング言語の概念の解説と、それがRustの文脈だとどうなるか。

変数と可変性

Rustでは変数は標準で不変だが、可変にする選択肢もある。なぜそうなっているのか。 cargo new --bin variables でプロジェクトを作って確認してみる。

fn main() {
    let x = 5;
    println!("The value of x is: {}", x);
    x = 6;
    println!("The value of x is: {}", x);
}

ビルドして実行する。

error[E0384]: cannot assign twice to immutable variable `x`
 --> src/main.rs:4:5
  |
2 |     let x = 5;
  |         - first assignment to `x`
3 |     println!("The value of x is: {}", x);
4 |     x = 6;
  |     ^^^^^ cannot assign twice to immutable variable

error: aborting due to previous error
  • 不変な変数に2回も代入できないのと、その該当箇所が表示されている
  • 最初に設定した変数が、のちに変更されてしまっているという見つけづらいバグを防ぐことができる
  • mut をつけることで可変にできる(mutable?)
  • トレードオフとして、バグの予防、パフォーマンスと簡潔性(メモリ)
cargo run
   Compiling variables v0.1.0 (file:///Users/yagyosan/develop/rust_study/variables)
    Finished dev [unoptimized + debuginfo] target(s) in 1.40s
     Running `target/debug/variables`
The value of x is: 5
The value of x is: 6

変数と定数(constants)の違い

定数の特徴は以下

  • mutが使えない(常に不変)
  • const キーワードで宣言し、必ず注釈しないといけない -> 次セクションで説明
  • グローバルスコープ含めてどんなスコープでも定義できる
  • 関数呼び出し結果や実行時に評価される値?にはセットできない
  • (すべて大文字かつアンダースコアで単語区切り)

シャドーイング

前に定義した変数と同じ名前の変数を新しく宣言でき、前の変数を覆い隠す(shadow)こと。「シャドーされた」などという。 mutと上書きの違いは以下の通り。

  • letを使わずに再代入をしようとすればコンパイルエラーになる
  • 実行的には新しい変数を生成することになるため、値の型を変えつつ異なる名前を考える必要がなくなる(ex. 文字列型から数値型への変換)
    • 逆にmutを使おうとすると、型が変更されない(=再代入になる)ためコンパイルエラーになる

データ型

Rustの値はすべてデータ型になる。スカラー型と複合型の2種類を見てみる。

  • 静的型付き言語: コンパイル時にすべての変数の型が判明している必要がある
  • コンパイラ: 値と使用方法に基づいて使用したい型を推論し、複数の方が推論される場合は型注釈をつける必要がある

スカラー

単独の値を示す。主に整数、浮動小数点数、論理値、文字の4つ。

  • 整数型
    • i32型がデフォルトのバリアント
    • iが符号付き(=正負を持つ)整数、uが符号なし、数字がビット数
    • 符号付き数値は「2の補数表現」で保持される 符号付きバリアント:-(2<sup>n-1</sup>)以上2<sup>n-1</sup>-1)以下の数値
      • nはビット数
    • 符号なしバリアント: 0以上2<sup>n</sup>-1以下の数値
    • isizeusizeはプログラムが動作しているコンピュータの種類(64ビットアーキテクチャなど)による
    • 整数リテラル(見たままの値ということ)はバイトリテラル以外は_表記ができる
  • 浮動小数点型
  • 論理値型
    • truefalse
  • 文字型

複合型

  • タプル型
    • 複数の型の何らかの値を一つの複合型にまとめ上げるもの
    • (,)で記述する
    • 変数はタプル全体に束縛されているため、値を取り出すインはパターンマッチングが必要
    • letとパターンを使って個別の変数にすることを「分配」と呼ぶ
    • タプルに.と直後にアクセスしたい値の番号をつければ直接タプルの要素にアクセスできる
  • 配列型
    • タプルとは違い、すべての要素が同じ型でなければならない
    • 他の言語と違い、固定長になっている
    • [,]で記述する
    • ベクタ型はサイズの伸縮が可能なので、どちらを使うべきか迷ったらベクタ型を使う
    • 要素にアクセスするには添字を使う[0]
    • 配列の長さを超える添字を使用した場合はコンパイルエラーになる