Progrust Library.

// 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

  1. Crates and source files — The Rust Reference ↩ ↩2

  2. std::process::Termination ↩

  3. std::process::ExitCode ↩

この辞書が使われているページ

backlinks 5

  1. 辞書クレート
  2. 辞書パニック
  3. 本動かして学ぶRustプログラミング問題集 › 第12章 OptionとResult
  4. 本動かして学ぶRustプログラミング問題集 › 第15章 ファイル分割とクレート
  5. 本動かして学ぶRustプログラミング問題集 › 第4章 関数