duankuai6991 2016-08-26 20:41
浏览 23
已采纳

初始化周期错误

I have autogenerated code. Simplified version:

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

I have error after compiling

./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

I need do recursive call at grammar because i have preprocessor operator "#include" for parsing other file.

Because it is autogenerated code i can only modify code in block A or in function B.

How can i break the initialization cycle ?

  • 写回答

1条回答 默认 最新

  • dongxun5349 2016-08-27 07:23
    关注

    This is the result of the package initialization where:

    Dependency analysis does not rely on the actual values of the variables, only on lexical references to them in the source, analyzed transitively.

    For instance, if a variable x's initialization expression refers to a function whose body refers to variable y then x depends on y.

    As in: "A reference to a variable or function is an identifier denoting that variable or function."

    Your example in a playground returns something more direct:

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

    There are techniques in Go for loose coupling, for instance interface.

    As an example (not optimal, but at least breaks the initialization cycle), you can in //A add:

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

    And in //B, the call to parseInclude() becomes:

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

    See Go plaground and click on Run: no more initialization loop.


    The OP Red Skotina used a different approach with an 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)
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 我想咨询一下路面纹理三维点云数据处理的一些问题,上传的坐标文件里是怎么对无序点进行编号的,以及xy坐标在处理的时候是进行整体模型分片处理的吗
  • ¥15 CSAPPattacklab
  • ¥15 一直显示正在等待HID—ISP
  • ¥15 Python turtle 画图
  • ¥15 关于大棚监测的pcb板设计
  • ¥15 stm32开发clion时遇到的编译问题
  • ¥15 lna设计 源简并电感型共源放大器
  • ¥15 如何用Labview在myRIO上做LCD显示?(语言-开发语言)
  • ¥15 Vue3地图和异步函数使用
  • ¥15 C++ yoloV5改写遇到的问题