Rustを極めたい - 1

前回の記事  
https://qiita.com/on_c98/items/a829d61973483921b9cb

# Rustのデータ型

Rustは静的型付け言語です。すべての値は型を持ちます。
Rustには下記のようなデータ型があります。

## スカラー型

### 整数型

- i8, i32, i64, i128, isize
- u8, u32, u64, u128, usize

`i`はinteger、`u`はunsigned integerを意味します。数字はそれぞれビット数を表しています。

`isize`と`usize`はそれぞれ実行環境に適したサイズになります。64ビットのプロセッサで動いている場合は64ビットに、32ビットのプロセッサで動いている場合は32ビットになります。

```rust
let negative_num: i32 = -1300;
let positive_num: u32 = 4000;
```

整数型は下記のような書き方をすることで16進数、8進数、2進数、バイト値を表現できます。読みやすくするためにアンダーバーを使い桁区切りをすることも出来ます。値には影響しません。（`1,000`のコンマのようなもの）

- アンダーバー: `1_000_000` （`1000000`と同値）
- 16進数: `0xff` 先頭にゼロと小文字のx（エックス）をつける。
- 8進数: `0o77` 前頭にゼロと小文字のo（オー）をつける。
- 2進数: `0b0000_1111` 先頭にゼロと小文字のb（ビー）をつける。
- バイト値: `b'a'` 小文字のb（ビー）とシングルクォーテーションをつける。シングルクォーテーションで囲った値は後に出てくる`char`型になりますが、先頭に`b`をつけることでバイト値として扱われます。

どの型を使用したらいいか分からない時は、`i32`を使用することが推奨されています。

### 浮動小数点数型

Rustの浮動小数点数型には下記の二種類の方があります。signedのみで、unsignedはありません。

- f32, f64

```rust
let fnum: f32 = 3.14;
```

### 演算子

Rustでは下記の演算子を利用できます。

- 加算: `1 + 2 `
- 減算: `10 - 3`
- 乗算: `4 * 3`
- 除算: `10 / 2`
- 剰余: `20 % 4`

違う型同士では計算できません。

```rust
let a = 3.14 * 10 // エラー

let b: i8 = 10;
let c: i32 = 100;
let d = b + c; // エラー
```

整数同士で計算を行った場合、結果は全て`i32`になるため、除算で余りが出た場合は切り捨てられます。

- `20 / 3`（答えは6になる）

下記のように記述すると`f64`として扱われます。

- `20.0 / 3.0`（答えは6.666666666666667になる）

`u8`や`f32`など他のサイズで受け取りたい場合は、格納する変数の型を指定するか、`as`句を用います。

- `let x: u8 = 100 + 155;`
- `let f = 20.0 as f32 / 3.0`

### 論理型

Rustの論理型は下記になります。

- bool

論理型は`true`と`false`の2値のみを持ちます。条件式に使用できます。

```rust
let is_true: bool = true;

if is_true {
    println!("yes, it is true.");
}
```

比較演算子を用いた式の結果は、論理型になります。

```rust
let correct: bool = 10 > 2; // true
let incorrect: bool = 3 == 5; // false
```

### 文字型

Rustの文字型には下記があります。

- char

```rust
let word: char = 'a';
```

一文字のみを表現します。文字をシングルクォーテーションで囲うことで文字型として扱われます。

後に出てくる`&str`や`String`とは別物になります。扱えるのは一文字のみで、複数文字は表現できません。

` let w = 'hello';` （エラー）

### 文字列リテラル型

文字列リテラル型には、下記があります。

- &str

こちらは`char`型と違い複数文字を扱うことができます。

`let sentence: &str = "hello world";`

`&`は参照を表します。Rust内で出てくる文字列リテラルはすべて参照になります。

文字列リテラルは常に固定値であり、値を変化させることができません。

## 複合型 compound types

### タプル tuple

- `(1,2,3)`

タプルは固定長のリストのようなものです。複数の型を保持できます。

タプルの値は`分割代入`という方法を用いて、変数に割り当てることができます。

```rust
let tuple: (i32,f64,char) = (-400, 5.421, 't');

// 分割代入
let (a, b, c) = tuple

println!("{a}"); // -400
println!("{b}"); // 5.421
println!("{c}"); // t
```

タプルの各要素には`tuple.[index]`のようにドットとインデックスを用いてアクセスできます。
インデックス外の要素にアクセスしようとした場合、コンパイルエラーになります。

```rust
let tuple = ("test", 100, -10);

println!("{}", tuple.0); // test
println!("{}", tuple.1); // 100
println!("{}", tuple.2); // -10
println!("{}", tuple.3); // コンパイルエラー
```

### 配列 array

- `[1,2,3]`

Rustのリストにはタプルの他に配列があります。タプルと違い全て同じ型になります。

他の言語と違い、Rustの配列は固定長になります。宣言時にサイズが決まっている必要があります。可変長の配列を使用したい場合、主に後に出てくる`Vec`型を用います。


`[型; サイズ]`のように記述します。

```rust
let array: [i32; 5] = [1,2,3,4,5];
```

下記のように記述することで、`0`という値を5つ持った配列を作成することができます。

```rust
let zeros = [0; 5]; // [0, 0, 0, 0, 0]
```

配列の各要素には、`array[index]`のように記述することでアクセスできます。
インデックス外の要素にアクセスしようとした場合、`panic!`例外が発生してプログラムが終了します。

そのような場合は`.get()`メソッドを用いると、戻り値がOption型になるので同時に例外処理を実装することができます。

```rust
let first = zeros[0];
let second = zeros[1];
let out_of_index = zeros[5]; // panic!
let without_panic = zeros.get(10).unwrap_or(&999);
println!("{}",without_panic) // 999
```

## 独自型

`struct`や`enum`を用いることで独自の型を宣言することができます。Rustには`class`は実装されておらず、`struct`がその代わりのような役目を果たします。実装方法は、別の章で解説します。今回は、Rustの標準ライブラリに実装されている方について簡単に説明していきます。

Rustの標準ライブラリには下記のような型が存在します。

### 構造体 struct

Rustの標準ライブラリに含まれる構造体は、スカラー型の拡張型のようなものが多いです。`String`や`Vec`は特に頻繁に使用され、関連するメソッドも多いです。

- `String`: 可変長の文字列型。`&str`と相互に変換できる。
- `Vec<T>`: ベクタ型。可変長の配列。固定長の配列がスタックだったの対し、こちらはヒープでメモリ上に値を格納する。
- `Box<T>`: ボックス型。Rustではデフォルトで値はスタックされるが、それをヒープ化する。`Box<i32>`のように用いる。
- `HashMap<K,V>`: ハッシュマップ型。他の言語の辞書型のようなもの。キーとバリューの組み合わせで値を格納する。

```rust
let hello: String = String::from("Hello");
let vector: Vec<i32> = Vec::new();
vector.push(10);
vector.push(50);
```

### 列挙子 enum

Rustの標準ライブラリには下記二つの列挙子が実装されています。二つは主に例外処理に用いられ、メソッドの戻り値をこれらの型でラッパーして返すことで、値を安全に処理することができます。

- `Result::{Ok<T>, Err<E>}`: リザルト型。OkとErrの2つの状態を持つ。
- `Option::{Some<T>, None}`: オプション型。Rustでは`NULL`を実装しない代わりに、こちらのオプション型を用いて表現する。

```rust
let ok: Result<i32, i32> = Reuslt::Ok(100);
let op: Option<i32> = Option::Some(0);
```

## 終わりに

[次回](https://qiita.com/on_c98/items/f6541d6d793ad2a0b75d)は各項目を掘り下げる前に、Rustの関数について書いていこうと思います。