2016-08-26 145 views
1

我有自动生成的代码。简化版本:初始化周期错误

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.功能代码

我怎样才能打破初始化周期?

回答

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) 
} 
+0

感谢。我打破与 变种gProxy语法 FUNC的init(){ gProxy =克 } FUNC parseInclude(文件名的字符串)(接口{},错误){ 得到循环,_:= ParseReaderProxy(文件名) 回报得到的, nil } func ParseReaderProxy(filename string)(interface {},error){ p:=&parser {filename:filename} return p。解析(gProxy) } 你的答案是其他方式,但似乎更好。 –

+0

@RedSkotina这确实会起作用。我已经将您的方法纳入答案中,以提高可见性(以及正确的格式) – VonC