entry_args

SKILL.md

仓颉语言命令行参数处理 Skill

1. main 函数获取命令行参数

1.1 基本规则

  • 仓颉的 main 函数可以接收一个 Array<String> 类型的参数,用于获取命令行参数
  • 每个包只允许定义一个 main 函数
  • main 函数不能有访问修饰符
  • 参数类型必须Array<String>,不支持其他类型
  • 返回类型可以是 Unit 或整数类型(如 Int64

1.2 有效的 main 函数签名

// 无参数
main(): Unit { }
main(): Int64 { return 0 }

// 带命令行参数
main(args: Array<String>): Unit { }
main(args: Array<String>): Int64 { return 0 }

1.3 使用示例

main(args: Array<String>): Unit {
    println("参数个数: ${args.size}")
    for (arg in args) {
        println(arg)
    }
}

运行:

$ cjc main.cj && ./main Hello World
参数个数: 2
Hello
World

注意args 不包含可执行文件名本身,只包含传递给程序的参数。


2. std.argopt — 命令行参数解析

导入import std.argopt.*

std.argopt 包提供了结构化的命令行参数解析能力,支持短选项、长选项、组合选项、可选值和必选值,适合开发 CLI 工具。

2.1 核心 API

类型 / 函数 签名 说明
parseArguments parseArguments(args: Array<String>, specs: Array<ArgumentSpec>): ParsedArguments 解析命令行参数
ParsedArguments options: ReadOnlyMap<String, String>, nonOptions: Array<String> 解析结果
ArgumentParseException 解析失败时抛出的异常

2.2 参数规范(ArgumentSpec)

构造器 说明
Short(Rune, ArgumentMode) 短选项(如 -v
Short(Rune, ArgumentMode, (String) -> Unit) 短选项 + 回调
Long(String, ArgumentMode) 长选项(如 --verbose
Long(String, ArgumentMode, (String) -> Unit) 长选项 + 回调
Full(String, Rune, ArgumentMode) 同时定义长短选项(如 --output / -o
Full(String, Rune, ArgumentMode, (String) -> Unit) 同时定义长短选项 + 回调
NonOptions((Array<String>) -> Unit) 非选项参数回调

2.3 参数模式(ArgumentMode)

模式 说明 长选项格式 短选项格式
NoValue 不接受值(开关标志) --flag -f
RequiredValue 必须提供值 --name=value--name value -n value-nvalue
OptionalValue 值可选 --name=value--name -nvalue-n

2.4 特殊规则

  • --(双横线)终止选项扫描,其后所有参数都被视为非选项
  • 短选项可以组合:如 -abc 等价于 -a -b -c(当 a、b、c 均为 NoValue 时)
  • 组合短选项中遇到非 NoValue 选项时,剩余部分作为该选项的值
  • 如果组合短选项字面值与某个长选项名相同,优先作为长选项解析
  • 同一选项多次赋值时,以最后一次的值为准

3. CLI 工具开发实战

3.1 基本参数解析(不带回调)

import std.argopt.*

main(args: Array<String>): Unit {
    let specs = [
        Short(r'v', NoValue),                     // -v 开关
        Long("output", RequiredValue),             // --output <file>
        Full("help", r'h', NoValue)                // --help 或 -h
    ]

    try {
        let result = parseArguments(args, specs)

        // 检查开关选项
        if (result.options.contains("help") || result.options.contains('h')) {
            println("Usage: mytool [-v] [--output <file>] <input>...")
            return
        }

        let verbose = result.options.contains('v')
        let output = result.options.get("output")  // ?String

        if (verbose) {
            println("Verbose mode enabled")
        }

        if (let Some(outFile) <- output) {
            println("Output file: ${outFile}")
        }

        // 非选项参数(如输入文件列表)
        println("Input files: ${result.nonOptions}")
    } catch (e: ArgumentParseException) {
        println("Error: ${e}")
        println("Usage: mytool [-v] [--output <file>] <input>...")
    }
}

运行:

$ ./mytool -v --output result.txt file1.txt file2.txt
Verbose mode enabled
Output file: result.txt
Input files: [file1.txt, file2.txt]

$ ./mytool --help
Usage: mytool [-v] [--output <file>] <input>...

3.2 带回调的参数解析

回调方式适合在解析时立即处理每个参数。注意:回调 lambda 中不能捕获外部 var 变量(仓颉语言限制),可通过 parseArguments 返回的结果获取选项值:

import std.argopt.*

main(args: Array<String>): Unit {
    let specs = [
        Short(r'v', NoValue),
        Long("output", RequiredValue),
        Full("config", r'c', RequiredValue) { v =>
            println("Loading config: ${v}")
        },
    ]

    try {
        let result = parseArguments(args, specs)
        let verbose = result.options.contains('v')
        let output = result.options.get("output") ?? ""

        println("Verbose: ${verbose}, Output: ${output}")
        println("Inputs: ${result.nonOptions}")
    } catch (e: ArgumentParseException) {
        println("Error: ${e}")
    }
}

3.3 完整 CLI 工具示例

import std.argopt.*
import std.fs.*
import std.io.*
import std.env.*

main(args: Array<String>): Unit {
    let specs = [
        Full("help", r'h', NoValue),
        Full("version", r'V', NoValue),
        Full("output", r'o', RequiredValue),
        Full("format", r'f', RequiredValue),
    ]

    var result: ParsedArguments
    try {
        result = parseArguments(args, specs)
    } catch (e: ArgumentParseException) {
        eprintln("Error: ${e}")
        eprintln("Try '--help' for more information.")
        exit(1)
    }

    let showHelp = result.options.contains("help") || result.options.contains('h')
    let showVersion = result.options.contains("version") || result.options.contains('V')
    let outputPath = result.options.get("output") ?? ""
    let format = result.options.get("format") ?? "text"
    let inputFiles = result.nonOptions

    if (showVersion) {
        println("mytool 1.0.0")
        return
    }

    if (showHelp || inputFiles.isEmpty()) {
        println("Usage: mytool [OPTIONS] <files>...")
        println("")
        println("Options:")
        println("  -h, --help              Show help message")
        println("  -V, --version           Show version")
        println("  -o, --output <file>     Output file (default: stdout)")
        println("  -f, --format <fmt>      Output format: text|json (default: text)")
        return
    }

    // 处理输入文件
    for (file in inputFiles) {
        if (!exists(file)) {
            eprintln("Error: file not found: ${file}")
            continue
        }
        let content = File.readFrom(file)
        println("Processing: ${file} (${content.size} bytes)")
    }
}

运行:

$ ./mytool --version
mytool 1.0.0

$ ./mytool -o out.json -f json input.txt
Processing: input.txt (1024 bytes)

$ ./mytool --help
Usage: mytool [OPTIONS] <files>...

Options:
  -h, --help              Show help message
  -V, --version           Show version
  -o, --output <file>     Output file (default: stdout)
  -f, --format <fmt>      Output format: text|json (default: text)

4. 快速参考

需求 做法
获取原始命令行参数 main(args: Array<String>)
解析结构化选项 import std.argopt.* + parseArguments()
定义开关标志(如 -v Short(r'v', NoValue)
定义必选值选项(如 --output file Long("output", RequiredValue)
同时支持长短选项(如 -o / --output Full("output", r'o', RequiredValue)
获取非选项参数(如文件列表) result.nonOptionsNonOptions { files => ... }
处理解析错误 try { ... } catch (e: ArgumentParseException) { ... }
终止选项扫描 命令行中使用 --,之后的参数都视为非选项
Weekly Installs
0
First Seen
Jan 1, 1970