Rust 基本文法 - 型引数 -
はじめに
前回の Rust 基本文法記事の続編(?)になります。
Rust を使っていると、ジェネリクスは当然のことながら、
型引数もテクニックのうちの一つとして覚えておきたいところです。必ずどこかで利用する場面が来ると思います。
Rust という言語において型を自在に操ることができれば怖いもの無し!
今回も Rust Playground にて一緒に手を動かしてみてください。
関数の型引数
型引数とは、ジェネリック型として引数に、特定の方に依存しない型を定義することを言います。
具体的に何かというと、前回紹介したプリミティブ型を使ったジェネリクスを例に出しながら紹介します。
以下の例ですと、print_name()
の引数には Vec<String>
を指定する必要があります。
そのため、Vec<u32>
といった型を指定すると、コンパイルエラーとなります。
fn main() {
let name_list = vec![
"Alice".to_string(),
"Bob".to_string(),
"Charlie".to_string(),
];
let age_list = vec![20, 25, 30];
fn print_name(list: Vec<String>) {
for name in list {
println!("{}", name);
}
}
print_name(age_list);
}
print_name()
を呼び出している最後の行で、
以下のようなエラーがでてしまいました。
当然と言えば当然なのですが、print_name()
という関数は Vec<String>
という限定された引数を受付ける関数なのです。
mismatched types
expected struct `Vec<String>`
found struct `Vec<{integer}>`
これを、型引数を活用したコードへとリファクタリングしていきます。
以下の例では、print_array()
には関数の横に、<T: Debug>
という記述と、
Vec<T>
という引数を受け付けるように実装されています。
<T>
とすることで任意の型を受け入れることができるようになるため、コンパイルエラーは発生しません。
use std::fmt::Debug;
fn main() {
let name_list = vec![
"Alice".to_string(),
"Bob".to_string(),
"Charlie".to_string(),
];
let age_list = vec![20, 25, 30];
fn print_array<T: Debug>(list: Vec<T>) {
for name in list {
println!("{:?}", name);
}
}
print_array(name_list);
print_array(age_list);
}
構造体の型引数
構造体(struct)の表現でも、型引数を活用する場面は出てきます。
以下の例では、User
構造体に <T>
を追加しており、age
プロパティの値として T
としています。
さらにnew
メソッドを定義し、<T>の値の age
を返すような処理を実装しています。
struct User<T> {
age: T,
}
impl<T> User<T> {
fn new(age: T) -> User<T> {
User { age }
}
}
fn main() {
let age_num = 26;
let age_str = "26";
let user_num = User::new(age_num);
let user_str = User::new(age_str);
println!("User age: {:?}", user_num.age);
println!("User age: {:?}", user_str.age);
}
このように実装することで、汎用性の高い構造体とすることができます。
おわりに
今回は型引数に関して紹介していきました。
ジェネリクス同様に、TypeScript等の言語でも利用することができるので、言語問わず抑えておきたいテクニックでした。
では、Cheers!
Discussion