2016-08-26 1 views
1

J'ai un code généré automatiquement. Version simplifiée:Erreur de cycle d'initialisation

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

J'ai erreur après la compilation

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

je dois faire appel récursif à la grammaire parce que j'ai opérateur préprocesseur « #include » pour l'analyse syntaxique autre fichier.

Parce qu'il est le code généré automatiquement je ne peux modifier le code dans le bloc A ou B. en fonction

Comment puis-je briser le cycle d'initialisation?

Répondre

3

Ceci est le résultat de la package initialization où:

analyse de dépendance ne repose pas sur les valeurs réelles des variables, uniquement sur les références lexicales à eux dans la source, analysé transitive.

Par exemple, si une variable d'expression d'initialisation de l » x se réfère à une fonction dont le corps se réfère à la variable y puis x dépend y.

Comme dans: "Une référence à une variable ou à une fonction est un identificateur désignant cette variable ou cette fonction."

Votre example in a playground retours quelque chose de plus 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 

Il y a techniques in Go for loose coupling, par exemple l'interface .

À titre d'exemple (pas optimale, mais au moins rompt le cycle d'initialisation), vous pouvez en //A ajouter:

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

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

Et //B, l'appel à parseInclude() devient:

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

Voir Go plaground et cliquez sur Run: pas plus initialization loop.


Le OP Red Skotina utilisé une approche différente avec un 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

merci. i rompre le cycle avec var gProxy grammaire func init() { gProxy = g } func parseInclude (string fileName) (interface {}, erreur) { obtenu, _: = ParseReaderProxy (fileName) retour obtenu, } func ParseReaderProxy (chaîne de nom de fichier) (interface {}, erreur) { p: = & parser {nomfichier: nomfichier} return p.analyser (gProxy) } votre réponse est d'une autre manière mais semble meilleure. –

+0

@RedSkotina Cela fonctionnerait aussi en effet. J'ai inclus votre approche dans la réponse pour plus de visibilité (et un formatage correct) – VonC