在Go中处理混合类型的哈希替代方法

在Go中处理混合类型的哈希替代方法,go,Go,我正在做一个编程练习来熟悉围棋。我目前正在编写一个解析器,将字符串解析为带参数的命令,例如: C w h Should create a new canvas of width w and height h. B x y c Should fill the entire area connected to (x,y) with "colour" c. Q Should quit the program. 起初,我开始使用散列来保存

我正在做一个编程练习来熟悉围棋。我目前正在编写一个解析器,将字符串解析为带参数的命令,例如:

C w h           Should create a new canvas of width w and height h.
B x y c         Should fill the entire area connected to (x,y) with "colour" c.
Q               Should quit the program.
起初,我开始使用散列来保存参数,例如
w
h
。但是这是不灵活的,正如您所看到的,
c
是一种颜色,它将是一个字符串,而其他参数是整数

我是这样开始的:

package main

import (
    "errors"
    "strconv"
    "strings"
)

type command struct {
    id   string
    args map[string]int // Won't work because args can be of mixed types
}

func parseCommand(input string) (command, error) {
    if input == "" {
        return command{}, errors.New("No input")
    }

    commandParts := strings.Split(input, " ")

    switch commandParts[0] {
    case "C":
        if (len(commandParts)) != 3 {
            return command{}, errors.New("C (create) requires 2 arguments")
        }

        w, err := strconv.Atoi(commandParts[1])

        if err != nil {
            return command{}, errors.New("width must be an integer")
        }

        h, err := strconv.Atoi(commandParts[2])

        if err != nil {
            return command{}, errors.New("height must be an integer")
        }

        return command{
            id: "create",
            args: map[string]int{
                "w": w,
                "h": h,
            },
        }, nil
    case "B":
        if (len(commandParts)) != 4 {
            return command{}, errors.New("B (Bucket Fill) requires 3 arguments")
        }

        x, err := strconv.Atoi(commandParts[1])

        if err != nil {
            return command{}, errors.New("x must be an integer")
        }

        y, err := strconv.Atoi(commandParts[2])

        if err != nil {
            return command{}, errors.New("y must be an integer")
        }

        return command{
            id: "bucketFill",
            args: map[string]int{
                "x": x,
                "y": y,
                "c": commandParts[3], // This should be a string!
            },
        }, nil
    case "Q":
        return command{
            id: "quit",
        }, nil
    default:
        return command{}, errors.New("Command not supported")
    }
}
我的问题是,如果我要返回的参数是可变的且具有混合类型,我应该如何将输入字符串解析为命令?谢谢

另外,命令可以自由输入,并在终端中修改假画布,例如:

enter command: C 20 4
----------------------
|                    |
|                    |
|                    |
|                    |
----------------------

// Didn't mention this one but it's a Line if you didn't guess
enter command: L 1 2 6 2
----------------------
|                    |
|xxxxxx              |
|                    |
|                    |
----------------------

您使用
命令的方法不正确。
命令
可以应用于画布。所以我们这样说:

type canvas struct{ ... }

type command interface {
    apply(canvas *canvas)
}
现在有几种命令,每种命令都有自己的参数。但是,当作为命令使用时,调用方不必关心这些参数是什么

type createCommand struct {
    width  int
    height int
}

func (c createCommand) apply(canvas *canvas) { ... }

type bucketFillCommand struct {
    x     int
    y     int
    color string
}

func (c bucketFillCommand) apply(canvas *canvas) { ... }

type quitCommand struct{}

func (c quitCommand) apply(canvas *canvas) { ... }
然后你可以解析它们(我可能会把所有的解析都拉到函数中,但这很好)

请注意,当某些操作失败时,此命令返回
nil
,而不是
command{}


您使用
命令的方法不正确。
命令
可以应用于画布。所以我们这样说:

type canvas struct{ ... }

type command interface {
    apply(canvas *canvas)
}
现在有几种命令,每种命令都有自己的参数。但是,当作为命令使用时,调用方不必关心这些参数是什么

type createCommand struct {
    width  int
    height int
}

func (c createCommand) apply(canvas *canvas) { ... }

type bucketFillCommand struct {
    x     int
    y     int
    color string
}

func (c bucketFillCommand) apply(canvas *canvas) { ... }

type quitCommand struct{}

func (c quitCommand) apply(canvas *canvas) { ... }
然后你可以解析它们(我可能会把所有的解析都拉到函数中,但这很好)

请注意,当某些操作失败时,此命令返回
nil
,而不是
command{}



命令和参数始终是字符串,因此通常存储为字符串。arg也常常依赖于顺序,所以我不明白为什么要有一个map。我想看看一些cli框架,看看它们是如何处理事情的(通常是使用类型化的结构和标志,而不是使用单个的
map[string]T
),您能为您的需求提供一个示例吗?因为我想用arg做算术,所以我认为最好先解析它们,而不是每次使用arg时都这样做。在本练习中,用户键入这些命令,我无法将其更改为标志,因为这是练习的要求。@Dominic使用golang命令行标志或使用intereface map[interface{}]T@Metalhead1247谢谢,因为我不能使用标志,我会尝试使用interfacesCommands和参数来完成它,参数总是字符串,因此,它们通常是这样存储的。arg也常常依赖于顺序,所以我不明白为什么要有一个map。我想看看一些cli框架,看看它们是如何处理事情的(通常是使用类型化的结构和标志,而不是使用单个的
map[string]T
),您能为您的需求提供一个示例吗?因为我想用arg做算术,所以我认为最好先解析它们,而不是每次使用arg时都这样做。在本练习中,用户键入这些命令,我无法将其更改为标志,因为这是练习的要求。@Dominic使用golang命令行标志或使用intereface map[interface{}]T@Metalhead1247谢谢,因为我不能使用标志,我将尝试使用interfacesEdit:谢谢!因此,采用画布结构的apply函数被使用,以便各种命令结构满足命令界面的要求?另外,如果我想检查返回命令的类型,例如,
quitCommand
如何执行?是的;当您调用
apply
时,这些命令执行它们应该对画布执行的任何操作。如果要检查特定命令,这只是一个两值类型断言:当调用
parseCommand
时,是否可以将命令转换为具体类型(例如,可以运行
command.width
),或者我必须执行
concreteCommand,ok:=command。(createCommand)
在新行/new var上?为什么要访问
命令。宽度
?这似乎不对。你应该在
apply
(在
apply
的内部,类型是结构)啊,是的,这很有意义,这只是为了测试编辑:谢谢!因此,采用画布结构的apply函数被使用,以便各种命令结构满足命令界面的要求?另外,如果我想检查返回命令的类型,例如,
quitCommand
如何执行?是的;当您调用
apply
时,这些命令执行它们应该对画布执行的任何操作。如果要检查特定命令,这只是一个两值类型断言:当调用
parseCommand
时,是否可以将命令转换为具体类型(例如,可以运行
command.width
),或者我必须执行
concreteCommand,ok:=command。(createCommand)
在新行/new var上?为什么要访问
命令。宽度
?这似乎不对。您应该在
apply
内部执行所有操作(在
apply
内部,类型是结构)啊,是的,这很有意义,这只是为了测试