1. 概述
本文将介绍如何使用 Kotlin 官方实验性库 kotlinx-cli 快速构建结构清晰、易于维护的命令行(CLI)应用程序。该库的核心功能是解析并校验来自命令行的参数,让你无需手动处理 args
数组,避免“自己造轮子”的踩坑经历。
对于熟悉 Java 或 Kotlin 的开发者来说,直接用 main(args)
手动解析参数不仅繁琐还容易出错。而 kotlinx-cli 提供了声明式 API,让 CLI 参数定义变得直观且类型安全。
2. 添加 Maven 依赖
在 pom.xml
中引入 kotlinx-cli 的 JVM 版本依赖:
<dependency>
<groupId>org.jetbrains.kotlinx</groupId>
<artifactId>kotlinx-cli-jvm</artifactId>
<version>0.3.5</version>
</dependency>
你可以在 Maven Central 查看最新版本。⚠️ 注意:当前为实验性库,正式环境使用前建议评估稳定性。
3. 参数处理机制
CLI 参数通常以 -
或 --
开头。要实现自动解析,我们需要创建一个 ArgParser
实例,它负责配置、验证和消费这些参数。
基础解析器示例
fun main(args: Array<String>) {
val parser = ArgParser("example")
parser.parse(args)
}
运行 example -h
即可看到自动生成的帮助信息:
Usage: example options_list
Options:
--help, -h -> Usage info
✅ 可见,-h
和 --help
已被自动支持,开箱即用。
3.1 可选参数(Optional Arguments)
为了让程序真正可用,我们需要定义具体的参数。通过调用 parser.option()
方法即可完成:
fun main(args: Array<String>) {
val parser = ArgParser("example")
val name by parser.option(
ArgType.String,
shortName = "n",
description = "User name"
)
parser.parse(args)
println("Hello, $name!")
}
这里使用了 Kotlin 的 委托属性(delegated properties),name
的值由解析器在 parse()
调用后自动注入。
运行 example -n John
输出:
Hello, John!
若未传参,name
为 null
(因为默认是可选的)。帮助信息中会显示:
Usage: example options_list
Options:
--name, -n -> User name { String }
--help, -h -> Usage info
其中 { String }
表示参数类型。支持的类型包括:
ArgType.String
ArgType.Boolean
ArgType.Int
ArgType.Double
ArgType.Choice
3.2 必填参数(Required Arguments)
通过 .required()
扩展函数将参数设为必填:
val name by parser.option(
ArgType.String,
shortName = "n",
description = "User name"
).required()
此时 name
变为非空类型(non-nullable),如果未提供 -n
参数,程序将抛出异常并打印提示:
Value for option --name should always be provided on the command line.
Usage: example options_list
Options:
--name, -n -> User name (always required) { String }
--help, -h -> Usage info
✅ 类型系统提前帮你拦截了空值风险,减少运行时错误。
3.3 默认值参数(Default Arguments)
使用 .default(value)
设置默认值:
val name by parser.option(
ArgType.String,
shortName = "n",
description = "User name"
).default("N/A")
帮助信息中会体现默认值 [N/A]
:
Usage: example options_list
Options:
--name, -n [N/A] -> User name { String }
--help, -h -> Usage info
运行时不带 -n
将输出 Hello, N/A!
⚠️ 注意:.required()
与 .default()
互斥,不能同时使用,否则编译或运行时报错。
3.4 多值参数(Multiple Arguments)
当需要接收多个相同类型的参数时,使用 .multiple()
:
fun main(args: Array<String>) {
val parser = ArgParser("example")
val names by parser.option(
ArgType.String,
shortName = "n",
description = "User name"
).multiple()
parser.parse(args)
names.forEach {
println("Hello, $it!")
}
}
命令行传参方式:example -n John -n Smith
输出:
Hello, John!
Hello, Smith!
此时 names
是 List<String>
类型,便于后续处理。
4. Choice 类型支持
ArgType.Choice
用于限制参数取值范围,防止非法输入。
4.1 枚举 Choice(Enum Choice)
推荐使用枚举类型,简洁又安全:
enum class Format {
HTML,
CSV,
PDF
}
fun main(args: Array<String>) {
val parser = ArgParser("example")
val format by parser.option(
ArgType.Choice<Format>(),
shortName = "f",
description = "Format for the output file"
)
parser.parse(args)
println("Hello, $format")
}
运行 example -f csv
输出 Hello, CSV
✅
若输入非法值如 example -f cs
❌,则报错:
Option format is expected to be one of [html, csv, pdf]. cs is provided.
Usage: example options_list
Options:
--format, -f -> Format for the output file { Value should be one of [html, csv, pdf] }
--help, -h -> Usage info
✅ 自动提示合法选项,用户体验友好。
4.2 自定义 Choice(Custom Choice)
也可以传入字符串列表定义选项:
fun main(args: Array<String>) {
val parser = ArgParser("example")
val typeFormat by parser.option(
ArgType.Choice(listOf("html", "csv", "pdf"), { it }),
shortName = "sf",
description = "Format as a string for the output file"
)
parser.parse(args)
println("Hello, $typeFormat")
}
其中 { it }
是转换函数,用于将输入映射到 choice 列表中的值。由于我们直接使用字符串,所以原样返回即可。
还可以组合使用扩展函数,例如设置默认值并允许多选:
val typeFormats by parser.option(
ArgType.Choice(listOf("html", "csv", "pdf"), { it }),
shortName = "sf",
description = "Format as a string for the output file"
).default("csv").multiple()
此时 typeFormats
类型为 List<String>
,默认包含 "csv"
。
5. 子命令(Subcommands)
当 CLI 工具功能较多时,使用子命令划分职责更清晰。比如 Git 中的 git commit
、git push
等。
定义子命令
继承 Subcommand
类并重写 execute()
方法:
class Multiply : Subcommand("mul", "Multiply") {
val numbers by argument(ArgType.Int, description = "Numbers").multiple(3)
var result = 0
override fun execute() {
result = numbers.reduce { acc, it -> acc * it }
}
}
注意:
- 使用
argument()
而不是option()
来定义位置参数(positional arguments) multiple(3)
表示至少需要 3 个整数execute()
在参数校验通过后自动调用
注册并使用子命令
fun main(args: Array<String>) {
val parser = ArgParser("example")
val outNumber by parser.option(ArgType.Int, "outer number", "o").default(0)
val multiple = Multiply()
parser.subcommands(multiple)
parser.parse(args)
println("Total ${outNumber.plus(multiple.result)}")
}
运行命令:example -o 4 mul 1 2 3
输出:Total 10
解释:
-o 4
是顶层选项mul
是子命令名1 2 3
是传递给Multiply
子命令的位置参数
✅ 结构清晰,逻辑解耦,适合复杂 CLI 应用。
6. 总结
通过本文我们掌握了使用 kotlinx-cli 构建专业级 CLI 应用的关键技巧:
- ✅ 使用
ArgParser
统一管理参数解析 - ✅ 支持可选、必填、默认、多值等常见参数模式
- ✅ 借助
Choice
实现枚举或自定义选项校验 - ✅ 利用
Subcommand
实现模块化命令设计 - ✅ 全程类型安全,减少 runtime error
虽然 kotlinx-cli 目前仍处于实验阶段,但其 API 设计简洁现代,非常适合 Kotlin 项目快速搭建 CLI 工具。如果你正在开发脚本类工具或微服务命令行入口,不妨试试这个轻量高效的解决方案。