Oshiro-lab.

Rust 学習記 #3 - Common Programming Concepts Part.1

2024-04-11

The Book の 3 章『Common Programming Concepts』を進めていく。

https://doc.rust-lang.org/book/ch03-00-common-programming-concepts.html

変数

Rust における変数はデフォルトで immutable となっており mut を付けることで mutable な変数となる。

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

上記のように immutable な変数 x に再代入しようとすると、

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

cannot assign twice to immutable variable というエラーが表示される。

定数

const STANDARD_GRAVITY: f32 = 9.80665;
println!("Standard gravity is {STANDARD_GRAVITY} m/s^2");

定数は const keyword で定義され、その値の型を注釈する必要がある。

定数はグローバルスコープを含めてどのスコープでも定義することができ、定義されたスコープ内で有効となる。

変数とは異なり mut を使うことはできず、常に immutable となる。

シャドーイング

fn main() {
    let x = 5;
    let x = x + 1;

    println!("The value of x is: {x}");

    {
        let x = x * 2;
        println!("The value of x in the inner scope is: {x}");
    }

    let x = x + 2;

    println!("The value of x is: {x}");
}

上記コードを実行すると、次のような出力となる。

The value of x is: 6
The value of x in the inner scope is: 12
The value of x is: 8

let keyword で同じ変数名を指定して再宣言することができる。

最初の let x = 5 に対して let x = x + 1 とすることで、この時点で x: 6 となっている。

直後のブロックスコープ内では直前の x の値が 6 なので、let x = x + 2x: 12 となる。

ブロックスコープを抜けるとシャドーイングが終了するので x の値は 6 となり、

その後の let x = x + 2 では x: 8 となる。

データ型

Rust は静的型付け言語のため、コンパイルの時点ですべての型が決まっている必要がある。

let guess = "614".parse().expect("Not a number!");

上記のコードを実行すると、以下のようなエラーが表示される。

$ cargo run
   Compiling variables v0.1.0 (/home/oshiroman/projects/learning_rust/chapter3)
error[E0284]: type annotations needed
 --> src/main.rs:2:9
  |
2 |     let guess = "614".parse().expect("Not a number!");
  |         ^^^^^         ----- type must be known at this point
  |
  = note: cannot satisfy `<_ as FromStr>::Err == _`
help: consider giving `guess` an explicit type
  |
2 |     let guess: /* Type */ = "614".parse().expect("Not a number!");
  |              ++++++++++++

For more information about this error, try `rustc --explain E0284`.
error: could not compile `variables` (bin "variables") due to 1 previous error

parse メソッドで文字列 → 数値へ変換する場合、型注釈またはターボフィッシュ parse::<T>() を指定する。

// 型注釈
let guess: u32 = "614".parse().expect("Not a number!");

// ターボフィッシュ
    let guess = "614".parse::<u32>().unwrap();

【参考記事】Rustで文字列を数値に変換(parse, from_str_radix)

スカラー型 - Scalar Types

スカラー型は単独の値を表し、整数、浮動小数点数、論理値、文字の 4 つの型がある。

整数型 - Integer Types

符号付き 32-bit 整数は i32 、符号なし 64-bit 整数は u64 のように表せる。

isizeusize は動作する環境に依存し、64-bit アーキテクチャであれば 64-bit 整数として振る舞う。

整数型の基準型は i32 となっている。

浮動小数点型 - Floating-Point Types

Rust の浮動小数点数は IEEE-754 に従っており f32 は単精度、 f64 は倍精度。

浮動小数点数の基準型は f64 となっている。

let x = 3.0;  // f64
let y: f32 = 2.7182818;

数値演算

// addition
let sum = 2 + 3;
println!("[sum] {sum}");

// subtraction
let diff = 1.732 - 2.236;
println!("[diff] {diff}");

// multiplication
let product = 12345679 * 23;
println!("[product] {product}");

// division
let quotient = 58.0 / 173.1;
let truncated = -2401 / 2443;
println!("[quotient] {quotient}");
println!("[truncated] {truncated}");

// remainder
let remainder = 341 % 17;
println!("[remainder] {remainder}");
[sum] 5
[diff] -0.5040000000000002
[product] 283950617
[quotient] 0.3350664355863663
[truncated] 0
[remainder] 1

論理値型 - The Boolean Type

bool 型と表され truefalse の二値。

// boolean
let t = true;
let f: bool = false;

文字型 - The Character Type

char 型と表され、シングルクォートで文字を囲う。

// character
let c = 'c';
let r = 'ℝ';
let zzz = '💤';

複合型 - Compound Types

タプル型 - The Tuple Type

タプルは複数の型を一つの複合型にまとめる。

// tuple
let tuple: (i32, f64, i8) = (2119, 9.8, -3);
let (a, b, c) = tuple;
println!("a: {a}, b: {b}, c: {c}");  // a: 2119, b: 9.8, c: -3

アクセスしたい値の番号を . で繋げて記述することで、タプルの要素にアクセスすることができる。

let tup = ("PERFECT", 100, false);
let perfect = tup.0;
let one_hundred = tup.1;
let f = tup.2;

println!("[perfect] {perfect} [one_hundred] {one_hundred} [f] {f}");
// [perfect] PERFECT [one_hundred] 100 [f] false

配列型 - The Array Type

配列はタプルと異なり、含まれる値はすべて同じ型でなければならない。

配列は固定長であるため、宣言後はそのサイズを変更することはできない。

可変長なコレクションを使用したい場合はベクタを使用する。

// array
let directions = ["North", "East", "South", "West"];
let east = directions[1];
println!("[1] {east}"); // [1] East

宣言時に要素の型と長さを指定したり、初期化する値を指定することもできる。

let all_u64: [u64; 10] = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29];
let all_zero = [0; 10];  // let all_zero = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] と同義
println!("{all_u64:?}");  // [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] 
println!("{all_zero:?}");  // [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

(c) 2015 - 2024 Tatsuya Oshiro