如何表达"切片(字符串或'其他此类切片')的类型"

Neu*_*onQ 7 types abstract-syntax-tree go algebraic-data-types

如何在Go中表达"(字符串或其他此类列表)列表"?基本上,好的''树表示为无限嵌套的列表列表和某些值作为值(本例中的字符串)"

我正在寻找一个S表达式(它本身就是最简单的AST)的最简单的表示形式,在Python中看起来像这样:

sexp1 = ["+", "x", "y", ["*", "10", "myVal"]]
sexp2 = ["foo" "bar" "baz"]
sexp3 = [ [ [["gooo"], "moo"] ], "too", ["yoo", "2"] ]
Run Code Online (Sandbox Code Playgroud)

Go中所有这些表达式都有哪些类型?显然[][]string不起作用,因为这不起作用:

func makeSexp(parserName string, values ...[][]string) [][]string {
    return append([]string{parserName}, values...)
}
Run Code Online (Sandbox Code Playgroud)

(编译错误:1.cannot use values (type [][][]string) as type []string in append,2 cannot use append([]string literal, values...) (type []string) as type [][]string in return argument.)

...虽然完全无类型的版本有效(但我不想完全放弃类型安全!):

func makeSexp(parserName string, values ...interface{}) interface{} {
    return append([]interface{}{parserName}, values...)
}
Run Code Online (Sandbox Code Playgroud)

Ain*_*r-G 5

不幸的是,Go不支持代数数据类型,因此最好使其类型安全的是创建一个未导出的接口,并进行两种实现:

type sExp interface {
    sExp()
}

type s string

func (s) sExp() {}

type l []sExp

func (l) sExp() {}

// ...
var sexp1 sExp = l{s("+"), s("1"), s("2"), l{s("*"), s("10"), s("myVal")}}
Run Code Online (Sandbox Code Playgroud)

这基本上是Protobuf编译器处理例如oneof案例的方式.这仍然需要很多类型的开关或类型断言来使用,但至少你可以确定你的模块之外的任何东西都不能修补它.

游乐场:https://play.golang.org/p/KOvFqJEvxZ.