我正在进行编程练习以熟悉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.
起初我开始使用散列来保存参数,例如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")
}
}
我的问题是,如果要返回的参数是变量且具有混合类型,我应该如何将输入字符串解析为命令?谢谢。
PS可以自由键入命令并在终端中修改假画布,例如:
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 |
| |
| |
----------------------
答案 0 :(得分:4)
您对command
的处理方式不正确。 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) { ... }
然后您可以解析它们(我可能会将所有解析放入函数中,但这很好)。
func parseCommand(input string) (command, error) {
if input == "" {
return nil, errors.New("No input")
}
commandParts := strings.Split(input, " ")
switch commandParts[0] {
case "C":
if (len(commandParts)) != 3 {
return nil, errors.New("C (create) requires 2 arguments")
}
w, err := strconv.Atoi(commandParts[1])
if err != nil {
return nil, errors.New("width must be an integer")
}
h, err := strconv.Atoi(commandParts[2])
if err != nil {
return nil, errors.New("height must be an integer")
}
return createCommand{width: w, height: h}, nil
case "B":
if (len(commandParts)) != 4 {
return nil, errors.New("B (Bucket Fill) requires 3 arguments")
}
x, err := strconv.Atoi(commandParts[1])
if err != nil {
return nil, errors.New("x must be an integer")
}
y, err := strconv.Atoi(commandParts[2])
if err != nil {
return nil, errors.New("y must be an integer")
}
return bucketFillCommand{x: x, y: y, color: commandParts[3]}, nil
case "Q":
return quitCommand{}, nil
default:
return nil, errors.New("Command not supported")
}
}
请注意,如果某件事失败,则返回nil
作为命令,而不是command{}
。