| name | cangjie-entry-args |
| description | 仓颉语言命令行参数处理。当需要了解仓颉 main 函数如何接收命令行参数、如何使用 std.argopt 包解析短选项/长选项/组合选项、如何开发 CLI 工具时,应使用此 Skill。 |
仓颉语言命令行参数处理 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 带回调的参数解析
回调方式适合在解析时立即处理每个参数:
import std.argopt.*
main(args: Array<String>): Unit {
var verbose = false
var output = ""
var inputs = Array<String>([])
let specs = [
Short(r'v', NoValue) { _ => verbose = true },
Long("output", RequiredValue) { v => output = v },
Full("config", r'c', RequiredValue) { v =>
println("Loading config: ${v}")
},
NonOptions { files => inputs = files }
]
try {
parseArguments(args, specs)
println("Verbose: ${verbose}, Output: ${output}")
println("Inputs: ${inputs}")
} 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 {
var showHelp = false
var showVersion = false
var outputPath = ""
var format = "text"
var inputFiles = Array<String>([])
let specs = [
Full("help", r'h', NoValue) { _ => showHelp = true },
Full("version", r'V', NoValue) { _ => showVersion = true },
Full("output", r'o', RequiredValue) { v => outputPath = v },
Full("format", r'f', RequiredValue) { v => format = v },
NonOptions { files => inputFiles = files }
]
try {
parseArguments(args, specs)
} catch (e: ArgumentParseException) {
eprintln("Error: ${e}")
eprintln("Try '--help' for more information.")
exit(1)
}
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.nonOptions 或 NonOptions { files => ... } |
| 处理解析错误 | try { ... } catch (e: ArgumentParseException) { ... } |
| 终止选项扫描 | 命令行中使用 --,之后的参数都视为非选项 |