英文:
How to express type of "slice of (string or 'other such slice')"
问题
如何在Go中表示“一个由字符串或其他类似列表组成的列表”类型?基本上是经典的“树表示为无限嵌套的列表和一些值(在这个例子中是字符串)”。
我正在寻找最简单的S表达式表示方式(它本身将是AST的最简单表示方式),在Python中看起来像这样:
sexp1 := []interface{}{"+", "x", "y", []interface{}{"*", "10", "myVal"}}
sexp2 := []interface{}{"foo", "bar", "baz"}
sexp3 := []interface{}{[][][]interface{}{{[]interface{}{"gooo"}, "moo"}}, "too", []interface{}{"yoo", "2"}}
在Go中,所有这些表达式的类型将是什么?显然,[][]string
不起作用,因为这样做不起作用:
func makeSexp(parserName string, values ...[][]string) [][]string {
return append([]string{parserName}, values...)
}
(编译错误: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...)
}
英文:
How can I express in Go a type which is "a list of (strings or other such lists)"? Basically the good ol' "tree represented as infinitely nested lists of lists and something as values (strings in this example)"
I'm looking for the simplest possible representation of an S-expression (which itself would be the simplest of an AST), which in Python would look like this:
sexp1 = ["+", "x", "y", ["*", "10", "myVal"]]
sexp2 = ["foo" "bar" "baz"]
sexp3 = [ [ [["gooo"], "moo"] ], "too", ["yoo", "2"] ]
What type would all these expressions have in Go? Obviously [][]string
doesn't work, as this doesn't work:
func makeSexp(parserName string, values ...[][]string) [][]string {
return append([]string{parserName}, values...)
}
(Compile errors: 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
.)
...while the fully untyped version works (but I don't want to completely give up type safety!):
func makeSexp(parserName string, values ...interface{}) interface{} {
return append([]interface{}{parserName}, values...)
}
答案1
得分: 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")}}
这基本上是Protobuf编译器处理oneof
情况的方式。虽然仍然需要大量的类型切换或类型断言来处理,但至少你可以确保模块外部的代码无法对其进行修改。
Playground: https://play.golang.org/p/KOvFqJEvxZ。
英文:
Unfortunately, Go doesn't support algebraic data types, so your best bet to make it type-safe is to create an unexported interface, and make two implementations of it:
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")}}
This is basically how Protobuf compilers deal with e.g. oneof
cases. This will still need a lot of type switches or type assertions to work with, but at least you can be sure that nothing outside of your module will be able to tinker with it.
Playground: https://play.golang.org/p/KOvFqJEvxZ.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论