StructOpt

構造体を定義することでコマンドライン引数をパースするライブラリ。現在はclapに統合されています。

rustcliderivestruct

フレームワーク

StructOpt

概要

StructOptは、構造体を定義することでコマンドライン引数をパースするライブラリです。derive マクロを使用して、Rust の構造体から自動的にコマンドライン引数パーサーを生成します。現在はclap v3以降にderiveマクロとして統合されており、新規プロジェクトではclap deriveの使用が推奨されています。

詳細

StructOptは、Rust の型システムとマクロシステムを活用して、宣言的なコマンドライン引数解析を可能にするライブラリとして開発されました。2018年頃から人気を集め、多くのRustプロジェクトで採用されました。しかし、2021年にclap v3がリリースされた際に、StructOptの機能がclapのderiveマクロとして統合されました。現在は新規開発は停止しており、既存のプロジェクトもclap deriveへの移行が推奨されています。

主な特徴

  • Derive マクロ: #[derive(StructOpt)]による自動パーサー生成
  • 型安全性: Rustの型システムを活用した強い型付け
  • 宣言的記述: 構造体定義でコマンドライン仕様を表現
  • サブコマンド: enum を使用したサブコマンドサポート
  • カスタマイズ: 属性による詳細なカスタマイズが可能
  • 自動ヘルプ: 構造体から自動的にヘルプメッセージを生成
  • clap統合: 内部でclapを使用(clap v3以降では逆に統合)

メリット・デメリット

メリット

  • 宣言的記述: 構造体定義でCLI仕様が明確に表現される
  • 型安全性: コンパイル時の型チェックによる堅牢性
  • 保守性: 構造体の変更が自動的にCLIに反映される
  • Rustらしさ: Rustの言語機能を最大限活用した設計
  • 学習コスト: 直感的で理解しやすいAPI

デメリット

  • 開発状況: 現在は開発が停止し、clap deriveへの移行が推奨
  • 新規採用: 新しいプロジェクトでは使用が推奨されない
  • 将来性: 長期的なサポートに不安がある
  • 移行コスト: 既存プロジェクトはclap deriveへの移行が必要

主要リンク

書き方の例

use structopt::StructOpt;
use std::path::PathBuf;

#[derive(StructOpt)]
#[structopt(name = "myapp", about = "ファイル処理アプリケーション")]
struct Opt {
    /// 詳細出力を有効にする
    #[structopt(short, long)]
    verbose: bool,

    /// 設定ファイルパス
    #[structopt(short, long, parse(from_os_str))]
    config: Option<PathBuf>,

    /// 処理するファイル数
    #[structopt(short = "n", long = "count", default_value = "1")]
    file_count: u32,

    /// 出力フォーマット
    #[structopt(short, long, possible_values = &["json", "yaml", "toml"], default_value = "json")]
    format: String,

    /// 入力ファイル(複数指定可能)
    #[structopt(name = "FILE", parse(from_os_str))]
    files: Vec<PathBuf>,
}

fn main() {
    let opt = Opt::from_args();

    if opt.verbose {
        println!("詳細モードが有効です");
        println!("設定ファイル: {:?}", opt.config);
        println!("ファイル数: {}", opt.file_count);
        println!("出力フォーマット: {}", opt.format);
    }

    for file in &opt.files {
        println!("処理中: {:?}", file);
        // ファイル処理ロジック
    }
}

// サブコマンドの例
#[derive(StructOpt)]
#[structopt(name = "git-clone", about = "Git風のサブコマンドアプリ")]
struct GitApp {
    #[structopt(subcommand)]
    cmd: Command,
}

#[derive(StructOpt)]
enum Command {
    /// リポジトリをクローンする
    Clone {
        /// リポジトリURL
        #[structopt(name = "REPO")]
        repository: String,
        
        /// ディレクトリ名
        #[structopt(name = "DIR")]
        directory: Option<String>,
        
        /// 浅いクローンを実行
        #[structopt(long)]
        depth: Option<u32>,
    },
    
    /// コミットを作成する
    Commit {
        /// コミットメッセージ
        #[structopt(short, long)]
        message: String,
        
        /// 全ての変更を含める
        #[structopt(short, long)]
        all: bool,
    },
    
    /// ステータスを表示する
    Status {
        /// 短い形式で表示
        #[structopt(short, long)]
        short: bool,
    },
}

fn main_with_subcommands() {
    let app = GitApp::from_args();

    match app.cmd {
        Command::Clone { repository, directory, depth } => {
            println!("クローン実行: {}", repository);
            if let Some(dir) = directory {
                println!("ディレクトリ: {}", dir);
            }
            if let Some(d) = depth {
                println!("深度: {}", d);
            }
        }
        
        Command::Commit { message, all } => {
            println!("コミット: {}", message);
            if all {
                println!("全ての変更を含めます");
            }
        }
        
        Command::Status { short } => {
            if short {
                println!("短いステータス表示");
            } else {
                println!("詳細ステータス表示");
            }
        }
    }
}

注意: StructOptは現在メンテナンスモードにあり、新規プロジェクトではclap v4の derive機能の使用が推奨されます。clap deriveは同様の機能を提供し、より活発に開発されています。