DevopsCamp 第 2 期作业: 《cobra – 05 Cobra 的子命令》 简单说下 cobra 命令树和 gin 路由树的实现差异

# DevopsCamp 第 2 期作业: 《cobra – 05 Cobra 的子命令》 简单说下 cobra 命令树和 gin 路由树的实现差异

**原文链接:** https://typonotes.com/posts/2023/02/14/devopscamp-cobra-05-subcommand/

## cobra 的子命令

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

“`go
var root = &cobra.Command{}

var child = &cobra.Command{}

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

没了, 应用上就这么多。

## cobra 命令树

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

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

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

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

“`go
// 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 // ???
// 省略
}
}
“`

**有一个疑惑点**, 想不通同一个 **子节点** 为什么可以挂多个 **父节点**? 为什么不会被覆盖掉? 以后想通了再填。

“`go
func init() {
root.AddCommand(sub1, sub_a)
sub1.AddCommand(sub_a)
}
“`

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

“`go
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()
}
}
“`

 

这种感觉, 特别像 **环太平洋2** 中的那个机械老鼠, 不仅可以独立执行命令, 还可以把大型怪兽“缝合”在一起。

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

## gin 的路由树

与 cobra 相比, gin 的路由树实现就是另外一种方式了, 我称之为 **生长**。 换句话说, gin 路由的子节点不能独立于父节点 **单独** 定义。

“`go
// Group creates a new router group. You should add all the routes that have common middlewares or the same path prefix.
// For example, all the routes that use a common middleware for authorization could be grouped.
func (group *RouterGroup) Group(relativePath string, handlers …HandlerFunc) *RouterGroup {
return &RouterGroup{
Handlers: group.combineHandlers(handlers),
basePath: group.calculateAbsolutePath(relativePath),
engine: group.engine,
}
}
“`

从上面代码可以看出来, `RouterGroup` 是通过 `Group` 方法实现路由节点 **生长** 的, 在调用 `Group` 方法的时候,
1. **必须** 要传入 **子节点** 的相对路径
2. 使用私有方法计算出 `basePath` 的值。

这个特别像怀孕生孩子, 一代接一代。 绝对错不了。 `O.o`。

![](https://static.tangx.in/posts/2023/02/14/devopscamp-cobra-05-subcommand/gin-router-tree-fs8.png)

### gin 的 RouterGroup 能实现 **认亲/挂靠** 模式吗?

肯定可以, 做个变形手术就好了。 这里挖个坑吧。

tangx
tangx

Go,云原生

文章: 2

留下评论

您的电子邮箱地址不会被公开。 必填项已用 * 标注