2016-08-26 8 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を参照する関数を参照する場合、xyに依存します。

as: "変数または関数への参照は、その変数または関数を示す識別子です。"より直接的

あなた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 Skotinapackage 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

おかげ。 iは VAR gProxy文法 FUNCのINIT() FUNCのparseInclude(ファイル名の文字列){ gProxy = G}(インターフェース{}、エラー){ が得たとのサイクルを破る、_:= ParseReaderProxy(filename)で リターンは、得nil } func ParseReaderProxy(filename string)(インターフェイス{}、エラー){ p:=&parser {filename:filename} return p。解析する(gProxy) } あなたの答えは他の方法ですが、より良いようです。 –

+0

@RedSkotinaそれは本当にうまくいくでしょう。私は、より多くの可視性(および適切な書式設定)のためにあなたのアプローチを答えに含めました。 – VonC