递归打印树状结构的完整列表时遇到一些问题

时间:2019-11-27 08:45:34

标签: go recursion struct slice

我无法为将具有 n 命令的CLI工具创建结构。每个命令可以具有 n 个子命令,每个子命令可以具有 n 个子命令。

我的问题是,在Go语言中,我正在努力寻找一种创建递归函数的方法,以输出每个命令的名称以及每个 n 子命令+每个 n 该子命令的子命令,在完整列表中。

例如,我希望获得以下输出:

1. command1
2. command2
3. command3
4. command3 subcommand1
5. command3 subcommand1 subcommand1
6. command3 subcommand2

这是我的代码:

package main

import (
    "fmt"
)

type command struct {
    name        string
    parent      *command
    subcommands []*command
}

func getLastCommand(c command) command {
    for _, s := range c.subcommands {
        if len(s.subcommands) == 0 {
            return *s
        }
        return getLastCommand(*s)
    }
    return c
}

func main() {
    cmdBase1 := command{
        name: "base1",
    }

    cmdBase2 := command{
        name: "base2",
    }

    var (
        cmdBase3,
        cmdBase3Sub1,
        cmdBase3Sub1Sub1,
        cmdBase3Sub2 command
    )

    cmdBase3 = command{
        name:        "base3",
        subcommands: []*command{&cmdBase3Sub1, &cmdBase3Sub2},
    }

    cmdBase3Sub1 = command{
        name:        "base3:sub1",
        parent:      &cmdBase3,
        subcommands: []*command{&cmdBase3Sub1Sub1},
    }

    cmdBase3Sub1Sub1 = command{
        name:   "base3:sub1:sub1",
        parent: &cmdBase3Sub1,
    }

    cmdBase3Sub2 = command{
        name:   "base3:sub2",
        parent: &cmdBase3,
    }

    // root commands
    commands := []command{
        cmdBase1,
        cmdBase2,
        cmdBase3,
    }

    for _, c := range commands {
        last := getLastCommand(c)
        fmt.Println(last.name)
    }
}

https://play.golang.org/p/HZPRlSghfAY

以下是当前输出:

base1
base2
base3:sub1:sub1

我想要的输出与上面的代码是:

base1
base2
base3
base3:sub1
base3:sub1:sub1
base3:sub2

我需要在代码中进行哪些更改,以便获得高于期望的输出?有没有我可以遵循的算法或数据结构来解决这个问题?我尝试了深度优先和二进制搜索,但是似乎无法将其塑造到我的结构中。

1 个答案:

答案 0 :(得分:3)

一个简单而优雅的解决方案是使用verbose_name_plural方法“武装” command。这可以打印其名称,并覆盖其子命令,并调用其print()(执行相同的操作):

print()

然后在func (c *command) print() { fmt.Println(c.name) for _, sc := range c.subcommands { sc.print() } } 中打印命令只是调用其main()方法(甚至不需要/使用print()):

getLastCommand()

这将产生所需的输出(在Go Playground上尝试):

for _, c := range commands {
    c.print()
}

请注意,当然base1 base2 base3 base3:sub1 base3:sub1:sub1 base3:sub2 不必一定是方法,它也可以是常规函数,在这种情况下,它看起来可能像这样:

print()

还有func print(c *command) { fmt.Println(c.name) for _, sc := range c.subcommands { print(sc) } } 中的循环:

main()

结果相同,请在Go Playground上尝试一下。

我也建议保持一致。如果您决定使用指向for _, c := range commands { print(&c) } 的指针,请在各处使用它(例如command中的commands切片存储非指针),这就是为什么必须将其元素地址传递给{ {1}}。