Rustは強い静的型付け言語なので、関数定義もそれを意識しておこなう必要があります。
関数定義の前に、まずは変数宣言から見てみましょう。Rustは型推論してくれるので、以下のように型を付けなくてもエラーにはなりません。が、やっぱり明示的に型を指定したいところ。
というわけで厳密に書くとなると、以下のようになるわけですが最初はなかなか慣れないと思います。
let foo: i32 = 100;
let 変数名: 型 = 値; という意味。数値型の場合は符号付きか否か、何ビットかでそれぞれ型名が異なってきます。ここでのi32は、符号付き32ビット、のこと。
C系など、静的型付け言語を普段から書いている人ならなんてことはないですが、Web系言語では意識することがあまりなかったりするのでちょっと取っ付きにくいかもです。
関数定義も似たような感じになります。与えられた数値に100を加えて返す関数を書いてみます。
fn add_hundred(foo: i32) -> i32 { foo + 100 }
見た目が少しアレですが、こういうもんだ、ということにしておきます。
引数がある場合、変数宣言のように型を省略するとコンパイルエラーになってしまうので注意です。なるほど、確かに引数は型推論ではなくて明示的に決めたいよね。でないと、関数内で意図しないバグが大量発生することがあるので。
他でもよく見られるように値を返すときはreturnが使えますが、Rust的には非推奨だそうです。なぜか、についてまとめてみます。
Rust推奨の書き方は、上の例のようにアロー演算子みたいに書くようです。何を渡して何が返ってくるかが一目瞭然ですね、これ好き。
さて、中身を見て気付くかと思われますが、セミコロンがないですね。セミコロンを付けなくてもいい、ではなく、セミコロンを付けたらダメ、なのです。試しにセミコロンを付けてコンパイルするとエラーになります。
error: not all control paths return a value fn add_hundred(x: i32) -> i32 { x + 100; } help: consider removing this semicolon: x + 100; ^
ここからわかるのは、Rustが文ではなく式ベース言語であるということと、セミコロンの意味が他言語とちょっと異なるということです。なるほどわからん。
式と文についておさらい。式は値を返すもの、文はそうでないもの、ですよね。Cの勉強をしていると、式の末尾にセミコロンを付けたものが文である、なんて説明をよく見かけますが…まぁいいや。
上の例の関数は返り値をi32の型と定義しています。しかしこれにセミコロンを付けてしまうと、i32ではなく空を返そうとするわけです。Rustはそこを察知し、なんか違う!とコンパイルエラーを出してくれるみたい。
ここでreturnの話に戻ると、returnはもちろん文になるのでセミコロンを付ければ正しく値を返せますが、式ベースのRustとしてはちょっと違くね?ということで非推奨みたいです。わかったような、わからないような。
兎にも角にも、Rustが非推奨しているなら使わないほうがいいです。今は非推奨でも将来的には仕様自体が消え去ることだってあるのだし。もちろん逆もあるけども。
ということで、以下のようになりました。
use std::io; fn main() { // 関数へのポインタは普通に代入演算子でいけます let f = add_hundred; // ちなみに省略せずに書くと // let f: fn(i32) -> i32 = add_hundred; let x = f(100); println!("the value is: {}", x); } fn add_hundred(foo: i32) -> i32 { foo + 100 }