はじめに
プログラミング言語 Rust は、高いパフォーマンスと信頼性を両立させる
現代的なシステムプログラミング言語として注目を集めています。
その特徴の一つが、強力な『 型 』システムです。
Rust の型は、コンパイル時に多くのバグを防ぎ、安全なプログラミングを可能にします。
メモリ安全性とスレッド安全性を保証しながら、高速な実行速度を実現できる理由の一つです。
本記事では、Rustの基本的な型について詳しく解説していきます。
スカラー型
整数型
符号あり整数型は i 、符号なし整数型は u で表します。
また、変数の大きさは、8bit、16bit、32bit、64bit、128bitが用意されています。
1 2 3 |
let x: i32 = 42; // 符号あり32ビット整数 let y: u64 = 100; // 符号なし64ビット整数 |
浮動小数点型
浮動小数点数型は f で表します。
また、変数の大きさは、32bit、64bitが用意されています。
1 2 3 |
let pie32: f32 = 3.14; let pie64: f64 = 3.14159265359; |
論理型
論理型は bool で表します。
1 2 3 |
let true_value: bool = true; let false_value: bool = false; |
文字型
文字型は char で表します。
1 2 |
let character: char = 'A'; // Unicode文字 |
複合型
タプル型
タプルは異なる型を収めることができる集合です。
そのため、関数から複数の値を返すときに、タプルでまとめて返すこともできます。
タプル内部の値にアクセスるときは、 .0 や .1 のようにドットと数値で指定します。
1 2 3 4 |
let mut tuple: (i32, f64, char) = (42, 3.14, 'A'); tuple.0 = 2; tuple.2 = 'B'; |
※タプル内の型を後から変更することはできません。
配列型
配列は、特定の型の値を連続に集めた集合です。
配列のサイズは固定で、コンパイル時に決まっている必要があります。
配列の内部の値にアクセスするときは、[ ] を使って要素を指定します。
また、参照するときは自動的にスライスとして扱われるため、範囲指定も可能です。
1 2 3 4 5 6 7 |
let mut array_a: [i32; 5] = [1, 2, 3, 4, 5]; let array_b: [i32; 3] = [0; 3]; // 0 で埋める array_a[1] = array_b[1]; println!("{:?}", &array_a[1..3]); // [1]から[3]の手前、つまり[2]までのスライス // [2, 3] |
スライス型
配列型で少し触れましたが、スライス型は配列やベクタの一部分を参照する型です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
// 配列の作成 let numbers = [1, 2, 3, 4, 5]; // スライスの作成(インデックス1から3まで) let slice = &numbers[1..4]; println!("スライス: {:?}", slice); // [2, 3, 4] // 先頭からのスライス let start_slice = &numbers[..3]; println!("先頭からのスライス: {:?}", start_slice); // [1, 2, 3] // 末尾までのスライス let end_slice = &numbers[2..]; println!("末尾までのスライス: {:?}", end_slice); // [3, 4, 5] // 全体のスライス let full_slice = &numbers[..]; println!("全体のスライス: {:?}", full_slice); // [1, 2, 3, 4, 5] |
文字列型
文字列スライス
文字列スライスは不変な参照で、文字列リテラルや String 型の一部分を参照します。
1 2 3 4 5 6 7 8 9 |
// 文字列リテラル(文字列スライス) let hello: &str = "こんにちは"; // 文字列スライスの一部を取り出す let str_slice = &hello[0..6]; // 注意: バイト単位での切り出しなので、日本語は注意が必要 println!("元の文字列: {}", hello); println!("スライス: {}", str_slice); |
String型
String 型は可変な文字列で、ヒープメモリに格納されます。
1 2 3 4 5 6 7 8 9 10 11 |
// 新しいString型の作成 let mut string = String::from("Hello"); // 文字列の追加 string.push_str(", World!"); // 文字列の変更 string = string.replace("Hello", "こんにちは"); println!("{}", string); |
文字列スライスとString型の相互変換
1 2 3 4 5 6 7 8 9 10 11 12 |
// &str から String への変換 let str_slice: &str = "Hello"; let string: String = str_slice.to_string(); // または let string: String = String::from(str_slice); // String から &str への変換 let string = String::from("World"); let str_slice: &str = &string; // または let str_slice: &str = string.as_str(); |
カスタム型
構造体
構造体は、関連するデータをグループ化するための基本的なカスタム型です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
// 基本的な構造体 struct User { username: String, email: String, active: bool, login_count: u64, } // 構造体のインスタンス化 let user1 = User { email: String::from("user@example.com"), username: String::from("username123"), active: true, login_count: 1, }; // タプル構造体 struct Color(i32, i32, i32); // タプル構造体の使用 let black = Color(0, 0, 0); |
列挙型
列挙型は、enum を使って定義することができます。
Rust の列挙型は、それぞれの列挙子にデータ付与できる点が特徴です。
1 2 3 4 5 6 7 8 9 |
enum Event { Quit, KeyDown(u8), MouseDown { x: i32, y: i32 }, } let e1 = Event::Quit; let e2 = Event::MouseDown { x: 10, y: 10 }; |
ジェネリック型
型パラメータ T を使用して、汎用的な実装が可能です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
// ジェネリック構造体 struct Point<T> { x: T, y: T, } // ジェネリックメソッドの実装 impl<T> Point<T> { fn new(x: T, y: T) -> Point<T> { Point { x, y } } } // 特定の型に対する実装 impl Point<f32> { fn distance_from_origin(&self) -> f32 { (self.x.powi(2) + self.y.powi(2)).sqrt() } } // 使用例 let integer_point = Point::new(5, 10); let float_point = Point::new(1.0, 4.0); println!("原点からの距離: {}", float_point.distance_from_origin()); |
標準ライブラリの代表的な型
Option型
Option 型は、値が存在するか否かを表現する列挙型です。
NULL の代替として使用されます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
// Option型の定義 enum Option<T> { Some(T), // 値が存在する None, // 値が存在しない } // Option型の基本的な使用例 let some_number = Some(5); let no_number: Option<i32> = None; // matchを使った値の取り出し match some_number { Some(i) => println!("値は{}", i), None => println!("値はありません"), } |
Result型
Result 型は、処理が成功したか失敗したかを表現する列挙型です。
エラーハンドリングに使用されます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// Result型の定義 enum Result<T, E> { Ok(T), // 成功時の値 Err(E), // エラー時の値 } fn divide(numerator: f64, denominator: f64) -> Result<f64, String> { if denominator == 0.0 { Err(String::from("0による除算はできません")) } else { Ok(numerator / denominator) } } |
おわりに
Rust の基本的な型について解説しました。
Rust の型は、コンパイル時のチェックによってメモリ安全性とスレッド安全性を保証します。
Rust での効率的なプログラミングの第一歩となることを願っています。