// dictionary
main関数.
main関数は、プログラムの実行が始まるエントリポイントです。実行可能ファイルになるバイナリクレートには必須で、クレートルートにmainという名前の関数が見つからないとコンパイルエラーE0601になります(ライブラリクレートはmainを持ちません)。
mainには引数を渡せず(E0580)、ジェネリクスの型引数やライフタイムパラメータとその境界も付けられません(E0131)。where句も書けません(E0646)。戻り値の型は標準ライブラリのstd::process::Terminationトレイトを実装した型に限られ、->を省略するとユニット型()を返す扱いになります1。
// プログラムの実行はここから始まる(->を省略しているので戻り値は())
fn main() {
let total = 1200 + 800; // 買い物かごの合計
println!("お支払い金額: {total}円");
}Playgroundで開く戻り値に取れる型
標準ライブラリにある主な実装は次のとおりです2。プログラムの終了コードは、返した値をこのトレイト経由で変換して決まります。
| 戻り値の型 | 終了コード | 用途 |
|---|---|---|
()(->の省略時) |
0 | 失敗を表現しない通常のmain |
Result<T, E>(T: Termination・E: Debug) |
OkはTに従い、ErrはFAILURE(主要な環境では1) |
Errのときエラー値を標準エラー出力へ表示 |
ExitCode |
保持している値そのもの | 終了コードを自分で決めたいとき(Rust 1.61で安定化)3 |
!(never型) |
―(到達しない) | std::process::exitなどで発散して戻らないとき |
Infallible |
―(到達しない) | 値を構築できず、失敗しえないことを型で示すとき |
戻り値をResult型にすると、mainの中でも?演算子で失敗を早期に返せます。返されたErrの後始末はランタイムが引き受けます。
fn main() -> Result<(), String> {
let input = "千二百"; // 数字として解釈できない入力
let price: u32 = input
.parse()
.map_err(|_| format!("価格を解釈できません: {input}"))?; // ここでErrを返すので以降は実行されない
println!("価格: {price}円");
Ok(())
}Playgroundで開く補足
mainはモジュールから持ち込んでもよい
mainはクレートルートにmainという名前で見えていればよく、定義そのものは別のモジュールにあっても構いません1。次のコードはuse宣言のasでapp::runにmainという別名を付けており、そのまま実行できます。
mod app {
pub fn run() {
println!("こんにちは");
}
}
use app::run as main;Playgroundで開く逆に、モジュールの中にmainを定義しただけではエントリポイントとは見なされず、E0601になります。
async fn mainは書けない
mainをasync fnにするとE0752になります。Rust本体に非同期ランタイムが含まれておらず、Futureを駆動する仕組みが標準では用意されていないためです。tokioなどが提供する#[tokio::main]属性は、async fn mainをランタイムの起動処理を含む通常のmainへ書き換えることで、この制約を回避しています。
Footnotes
この辞書が使われているページ
backlinks 5