/** * 第 10 章 · 实战项目 — 命令模型 + 解析器 * * 用 sealed class 表示"命令是这几种之一",配合 when 表达式,编译器 * 强制覆盖所有分支,新增命令时不会漏。 */ sealed class Command { data class Add(val title: String, val priority: Priority, val due: String?) : Command() data class Done(val id: Int) : Command() data class Remove(val id: Int) : Command() data class List(val filter: Filter) : Command() object Stats : Command() object Help : Command() enum class Filter { ALL, ACTIVE, DONE } } object CommandParser { fun parse(args: Array): Command { if (args.isEmpty()) return Command.Help return when (val cmd = args[0].lowercase()) { "add" -> parseAdd(args.drop(1)) "done" -> Command.Done(args.getOrNull(1)?.toIntOrNull() ?: error("done 需要数字 id")) "rm", "remove" -> Command.Remove(args.getOrNull(1)?.toIntOrNull() ?: error("rm 需要数字 id")) "list", "ls" -> Command.List(parseFilter(args.getOrNull(1))) "stats" -> Command.Stats "help", "-h", "--help" -> Command.Help else -> error("未知命令: $cmd(用 todo help 查看用法)") } } private fun parseFilter(s: String?): Command.Filter = when (s) { "active" -> Command.Filter.ACTIVE "done" -> Command.Filter.DONE null, "all" -> Command.Filter.ALL else -> error("未知 filter: $s(可选 active / done / all)") } private fun parseAdd(args: kotlin.collections.List): Command.Add { require(args.isNotEmpty()) { "add 需要标题" } val title = args[0] var priority = Priority.MID var due: String? = null var i = 1 while (i < args.size) { when (args[i]) { "--priority", "-p" -> { val v = args.getOrNull(++i) ?: error("--priority 需要值") priority = runCatching { Priority.valueOf(v.uppercase()) } .getOrElse { error("无效优先级: $v(可选 LOW / MID / HIGH)") } } "--due", "-d" -> { due = args.getOrNull(++i) ?: error("--due 需要值") } else -> error("未知参数: ${args[i]}") } i++ } return Command.Add(title, priority, due) } }