从结构与 Tag 构建命令体系
BuildFrom Example
构造根命令以及整个命令体系可以采用如下的方案:
- traditional stream calls (
app.Cmd("verbose", "v").Action(onVerbose)
) - concise modes by
[Create]
and cmd/xxcmd.go - use
[Create.BuildFrom]
to build cmdsys from a struct value via[App.FromStruct]
, see example #example_Create_buildFromStructValue
Getting started from New or Create function.
从结构定义中提取信息并构建 RootCommand 及其子命令系统是从 v2.1.36 开始引入的。
在 v2.1.37 中,我们进一步拓展了此功能,使其能够被用于子命令。
这个特性类似于 kong 那样的构造风格,但较为简陋。不过它的能力并未受到限制,相反,你仍然可以通过 With()
/Action
方法来进一步定制她。
一般地,可以使用如下的 Struct Tag 名字:
title
,name
:指定 Long titleshorts
,short
:逗号分隔的 Short Titles,其中第一个 title 被用于 Cmd/Flag.Short 字段,其它的被用于 ExtraShorts 字段aliases
,alias
:指定 Long Alias titlesdesc
,help
:指定 Desc 字段,用于帮助屏显示group
:指定 Group 字段required
:仅对 Flag 有效,指定 Flag.Required 属性。例如required:"true"
env
,envvars
:仅对 Flag 有效,指定 Flag.EnvVars 属性。你可以指定逗号分隔的多个值,例如:env:"USER,USERPROFILE"
head-like
,headLike
:仅对 Flag 有效,指定 Flag.HeadLike 属性。你可以指定一个布尔量来使能 head-like 能力,例如head-like:"true"
。cmdr
: 这个键包含特定能力。当前支持两个值:cmdr:"-"
: 忽略该字段cmdr:"positional"
: 如果该字段为[]string
类型,那么它将接受该 struct 所对应命令的 Positional Args 处理结果。
- 其它名字被忽略,未来可能就此在兼容性上做更多工作
值得一提的是,从 v2.1.28 开始,我们支持结构变量的反向绑定,因此 cmdr 对命令行参数的处理结果均将回写到对应的结构变量中。后文 反向绑定 将会对此介绍。
运行效果如下:
rm full
子命令的运行效果如下:
使用 With 进行定制
在测试代码中我们也给出了增强的例子。
通过 Create().BuildFrom(R{})
可以就下例构建出新的菜单结构。
通过为 struct A 增加 With()
方法,你可以对其进一步进行定制,如果传统方案所做的那样。
增加 Action
在上一个例子中,可以为 E,F 子命令增加 OnAction,
如此一来,子命令被执行时,Action 方法就将获得执行权。
你也可以为其他层次的子命令添加 Action,它们也能工作,但不被推荐,因为最终用户可能期待中间层次的命令自动显示帮助屏而不是执行某种行为。
指定默认值
在构建命令系统时,可以通过给结构变量指定初值的方式来给出 Flag 的默认值,
用于子命令
基本用法
我们已经达成了目标:现在可以在子命令构造时直接引入 struct 定义的命令子系统了。
通过这种方法,有可能简化复杂命令子系统的代码书写问题。
你可以将该能力简单地用于简化代码书写。所以下面的示例中我们就地构造一个 root{}
并利用该结构变量的值完成子命令系统的构建工作。
随后 root{}
就被 Go 回收了。
这种方法适合大多数情况。你将通过典型的 cmdr.Store()
/cmd.Store()
的方式访问命令行参数解析结果。并且不仅如此,在 Store
所提供的一致化界面下,你可以以统一的方式访问所有的配置数据集,这包括了命令行参数解析结果、环境变量、外部配置文件,远程配置中心等等。
其运行效果类似于:
反向绑定用法
如果你习惯于使用其他的命令行参数处理软件包,例如 flag
等等,它们习惯于以各种方式将每一条命令行参数和一个变量相互绑定,如同 task := flag.String("task", "", "The task you want to add to your to-do list")
所做的那样,然后你通过 *task
来访问 --task=abc
的解析结果。
更多的其他第三方库,对此还有进一步的拓展。
这种思路的有利之处显而易见,直观。某些第三方库能够在通过 struct Tag 构造命令系统的同时将 struct 变量与解析结果相互绑定,于是像 TLS 参数包等等就可以以一个 struct 的方式被管理起来。
同样的能力,我们在 v2.1.38 中完成了对此的支持。
对于上一节的例子,你只需要简单地提供一个 struct 变量值的指针作为 FromStruct 的参数,就能获得该能力。
这意味着你将会持久化这个 root 结构的变量。
下面的例子是向你展示如何有效地管理它,如何通过 s.root
取得命令行参数的解析结果。这个示例片段可以被集成到任何 blueprint 示例程序的体系结构中。
代码块中的高亮行是显著有别于上一节例子的部分。
其运行效果类似于:
考察该运行结果,Fa2:yes,man! Fa3:[jesus]
表示变量回写成功了,而且 positional-args 也记录了;另外,F2:ok
也代表着变量正确回写了。
上述的这些能力,主要目的在于提供更多的跨库的兼容性,以及针对特定类型的任务简化代码编写。
未来的计划
我们将来未来的几个版本迭代中,进一步地将 struct value 风格与 blueprint app 骨架结合起来,让你更简便快速地构建大型的命令体系结构,同时也不必失去精细控制能力。
同时,传统的构造方案并不受到影响。
:end:
How is this guide?
Last updated on