初始化周期错误

时间:2016-08-26 20:41:20

标签: go

我有自动生成的代码。简化版:

package main

// begin of A
func main(){
    ParseReader("x")
}
func parseInclude(fileName string) (interface{}, error) {
    got, _ := ParseReader(fileName)
    return got, nil
}
// end of A
type grammar struct {
    pos   int
    run  func(*parser) (interface{}, error)
}
var g = &grammar{
    pos:  1,
    run: (*parser).callonIncludeOp1,
}

type parser struct {
    filename string
    cur      current
}
func (p *parser) callonIncludeOp1() (interface{}, error) {
    return p.cur.onIncludeOp1("x")
}
func (p *parser) parse(g *grammar) (val interface{}, err error) {
    return g.pos, nil
}

type current struct {
    pos  int 
}
// B
func (c *current) onIncludeOp1(qfilename interface{}) (interface{}, error) {
    got, _ := parseInclude("x")
    return got, nil
}

func ParseReader(filename string) (interface{}, error) {
    p := &parser{ filename: filename }
    return p.parse(g)
}

编译后我有错误

./prog.go:19: initialization loop:
    /home/gCDfp4/prog.go:19 g refers to
    /home/gCDfp4/prog.go:25 (*parser).callonIncludeOp1 refers to
    /home/gCDfp4/prog.go:36 (*current).onIncludeOp1 refers to
    /home/gCDfp4/prog.go:7 parseInclude refers to
    /home/gCDfp4/prog.go:41 ParseReader refers to
    /home/gCDfp4/prog.go:19 g

我需要在语法上进行递归调用,因为我有预处理器操作符" #include"用于解析其他文件。

因为它是自动生成的代码,所以我只能修改块A或函数B中的代码。

如何打破初始化周期?

1 个答案:

答案 0 :(得分:3)

这是package initialization所在地的结果:

  

依赖性分析不依赖于变量的实际值,仅依赖于源中对它们的词汇引用,并且可以传递地进行分析。

     

例如,如果变量x的初始化表达式引用其主体引用变量y的函数,则x取决于y

     

如同:"对变量或函数的引用是表示该变量或函数的标识符。"

您的example in a playground会更直接地返回内容:

tmp/sandbox395359317/main.go:21: initialization loop:
    prog.go:21 g refers to
    prog.go:28 (*parser).callonIncludeOp1 refers to
    prog.go:21 g

techniques in Go for loose coupling,例如接口

作为一个例子(不是最优的,但至少打破了初始化周期),你可以在//A添加:

type parseIncluder interface {
    parseInclude(fileName string) (interface{}, error)
}

func (c *current) parseInclude(fileName string) (interface{}, error) {
    return parseInclude(fileName)
}

//B中,对parseInclude()的调用变为:

got, _ := c.cParseIncluder().parseInclude("x")

请参阅Go plaground并点击Run:不再initialization loop

OP Red Skotina使用了与package init() function不同的方法:

var gProxy grammar

func init() { gProxy = g }
func parseInclude(fileName string) (interface{}, error) {
    got, _ := ParseReaderProxy(fileName)
    return got, nil
}
func ParseReaderProxy(filename string) (interface{}, error) {
    p := &parser{filename: filename}
    return p.parse(gProxy)
}