首页 > 其他分享 >Golang 的 cobra 是如何实现使用链表实现命令树的

Golang 的 cobra 是如何实现使用链表实现命令树的

时间:2023-02-17 22:01:27浏览次数:62  
标签:Golang cobra AddCommand commands 链表 命令 Command 节点

Golang 的 cobra 是如何实现使用链表实现命令树的

在 cobra 中, 每个 命令 都是独立的。 通过 parent.AddCommand(children) 的形式进行串连。

var root = &cobra.Command{}

var child = &cobra.Command{}

func init() {
	root.AddCommand(child)
}

没了, 应用上就这么多。

cobra 命令树

如果你用过 gin 的路由树的话, 可能会对 cobra 的命令树实现更为深刻。

删除多余的结构, cobra 节点 就是下面这样的。

type Command struct {
	// 子命令
	commands []*Command
	// 父命令
	parent *Command
}

当进行 命令树 组合的时候, 是通过 领养/挂靠 的方式实现的。

// AddCommand adds one or more commands to this parent command.
func (c *Command) AddCommand(cmds ...*Command) {
	for i, x := range cmds {
		if cmds[i] == c {
			panic("Command can't be a child of itself")
		}

		// 为子命令设置父命令(认亲)
		cmds[i].parent = c // (1)
// 省略
		// 添加传入的子命令
		c.commands = append(c.commands, x) // (2)
	}
}

(1) 在我们可以在任意节点调用 Execute 方法, 这个调用会通过 递归 找到最上层的 节点。

func (c *Command) Execute() error {
	_, err := c.ExecuteC()
	return err
}

// ExecuteC executes the command.
func (c *Command) ExecuteC() (cmd *Command, err error) {
	// Regardless of what command execute is called on, run on Root only
	// 递归寻找最上层
	if c.HasParent() {
		return c.Root().ExecuteC()
	}
}

再来看一次 Command 结构体定义

type Command struct {
	// 子命令
	commands []*Command
	// 父命令
	parent *Command
}

(2) 通过将传入的命令保存到 []*Command 切片中, 实现了命令树的 组合

c.commands = append(c.commands, x) // (2)

且同时 实现了 同一个命令挂载到多个父命令上

root.AddCommand(sub1, sub2) // (a)
sub1.AddCommand(sub2) // (b)

commands 是一个切片, 用于保存 挂载 上来的子命令。 但是, 这里需要注意, 由于 *Command 是指针类型, 意味着在任何修改, 都可能影响其他调用的地方。

对于 sub2 而言, (a)处父节点是 root(b)处父节点是 sub1最终父节点是 sub1。 但不影响 sub2 同时是 rootsub1 的子命令。

总体来说, cobra 命令节点 独立而又统一

互相吹捧, 共同进步

欢迎和我一起学习进步, 如果有什么问题, 可以给我私信留言。 或者

  1. 加我好友 线下讨论。
  2. 关注我的 公众号 - Go与云原生 或者 B站账户 - 老麦胖熊猫 订阅最新文章和更多精彩内容

标签:Golang,cobra,AddCommand,commands,链表,命令,Command,节点
From: https://blog.51cto.com/bashrc/6064538

相关文章

  • 算法刷题-Excel表列序号、单词拆分 II、排序链表
    Excel表列序号(数学、字符串)给你一个字符串columnTitle,表示Excel表格中的列名称。返回该列名称对应的列序号。例如,A->1B->2C->3...Z->26AA->27AB->......
  • golang 入门(七) 接口-多态
    所谓多态就是子类在继承了父类后,自己重新写了一个方法覆盖父类的同名方法。继续引用上文的案例,父类computer中有PowerOff方法,但是子类laptop把盖子合上也可以认为是一种Powe......
  • golang串口通讯
    com.gopackagemainimport( "encoding/hex" "errors" "io" "strings" "time" "github.com/jacobsa/go-serial/serial" log"github.com/sirupsen/logrus")/......
  • 链表
    参考图中删除节点的链表,写出单链表插入和删除一个节点的伪代码算法。节点包含数据data和链接next单链表插入定义链表a=[a₁,a₂,a₃······ai-1,ai+1······......
  • DS-单链表:在单链表中元素值等于key的所有结点前插入一个元素值为x的新结点
    一、定义单链表结构代码:typedefintlinkType; ///<定义链表结点数据域数据类型///@brief链表结点定义typedefstructt_linkNode{structt_lin......
  • DS-单链表:单链表尾插法
    一、定义单链表结构代码:typedefintlinkType; ///<定义链表结点数据域数据类型///@brief链表结点定义typedefstructt_linkNode{structt_lin......
  • DS-单链表:单链表头插法
    一、定义单链表结构代码:typedefintlinkType; ///<定义链表结点数据域数据类型///@brief链表结点定义typedefstructt_linkNode{structt_lin......
  • DS-单链表:单链表尾删法
    一、定义单链表结构代码:typedefintlinkType; ///<定义链表结点数据域数据类型///@brief链表结点定义typedefstructt_linkNode{structt_lin......
  • DS-单链表:单链表头删法
    一、定义单链表结构代码:typedefintlinkType; ///<定义链表结点数据域数据类型///@brief链表结点定义typedefstructt_linkNode{structt_lin......
  • DS-单链表:指定位置插入新结点
    一、定义单链表结构代码:typedefintlinkType; ///<定义链表结点数据域数据类型///@brief链表结点定义typedefstructt_linkNode{structt_lin......