How do I split a package into multiple files when there are dependencies between their init() functions?

huangapple go评论85阅读模式
英文:

How do I split a package into multiple files when there are dependencies between their init() functions?

问题

我有一个go文件的包,变得难以管理,所以我想将它拆分成多个逻辑文件。

我目前将文件拆分(并缩写)如下:

// node.go
package schema

import (
"github.com/graphql-go/graphql"
"github.com/graphql-go/relay"
)

var nodeDefinitions *relay.NodeDefinitions

func init() {
nodeDefinitions = relay.NewNodeDefinitions(relay.NodeDefinitionsConfig{
IDFetcher: func(id string, info graphql.ResolveInfo) interface{} {
...
},
TypeResolve: func(value interface{}, info graphql.ResolveInfo) *graphql.Object {
// 根据值的类型返回GraphQLObjectType
switch value.(type) {
default:
return testType // 依赖于test.go
}
},
})
}

// root.go
package schema

import (
"github.com/graphql-go/graphql"
)

var Schema graphql.Schema

func init() {
queryType := graphql.NewObject(graphql.ObjectConfig{
Name: "Query",
Fields: graphql.Fields{
"version": &graphql.Field{
Type: versionType, // 依赖于testtype.go
...
},
"node": nodeDefinitions.NodeField, // 依赖于node.go
},
})

Schema, _ = graphql.NewSchema(graphql.SchemaConfig{
    Query: queryType,
})

}

// testtype.go
package schema

import (
"github.com/graphql-go/graphql"
"github.com/graphql-go/relay"
)

var testType *graphql.Object

func init() {
testType = graphql.NewObject(graphql.ObjectConfig{
...
Interfaces: []*graphql.Interface{
nodeDefinitions.NodeInterface, // 依赖于node.go
},
})
}

然后我在main.go中使用该包:

result := graphql.Do(graphql.Params{
Schema: schema.Schema,
RequestString: r.URL.Query()["query"][0],
})

虽然包可以正确构建,但在运行时会报错:

panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x1 addr=0x0 pc=0x48e4b6]

goroutine 1 [running]:
test/testproject/vendor/github.com/graphql-go/graphql.(*Object).Error(0x0, 0xc082003380, 0x3c)
C:/go/src/test/testproject/vendor/github.com/graphql-go/graphql/definition.go:440 +0x26
test/testproject/vendor/github.com/graphql-go/graphql.defineFieldMap(0xda48b0, 0xc08206c780, 0xc0820550e0, 0xda
C:/go/src/test/testproject/vendor/github.com/graphql-go/graphql/definition.go:498 +0x532
test/testproject/vendor/github.com/graphql-go/graphql.(*Object).Fields(0xc08206c780, 0xc08206c780)
C:/go/src/test/testproject/vendor/github.com/graphql-go/graphql/definition.go:416 +0x106
test/testproject/vendor/github.com/graphql-go/graphql.typeMapReducer(0xc082055110, 0xda4560, 0xc08206c780, 0x0,
C:/go/src/test/testproject/vendor/github.com/graphql-go/graphql/schema.go:208 +0x79a
test/testproject/vendor/github.com/graphql-go/graphql.NewSchema(0xc08206c780, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
C:/go/src/test/testproject/vendor/github.com/graphql-go/graphql/schema.go:67 +0x809
test/testproject/schema.init.2()
C:/go/src/test/testproject/schema/root.go:37 +0x244
test/testproject/schema.init()
C:/go/src/test/testproject/schema/version.go:37 +0x5b
main.init()
C:/go/src/test/testproject/main.go:37 +0x42

这是因为:

node.go 依赖于 testtype.go
testtype.go 依赖于 node.go
root.go 依赖于 node.go 和 testtype.go

go build按照文件名的字母顺序构建文件:先是node.go,然后是root.go,最后是testtype.go

如果我将root.go重命名为z.go,它就可以正确构建和运行。除了将root.go重命名为z.go这种不太理想的方法之外,还有其他方法可以以可扩展的方式解决这个问题吗?

英文:

I have a go file for a package that is becoming unwieldy, so I want to split it into multiple logical files.

I have the files currently split (and abridged) like so:

// node.go
package schema

import (
	"github.com/graphql-go/graphql"
	"github.com/graphql-go/relay"
)

var nodeDefinitions *relay.NodeDefinitions

func init() {
	nodeDefinitions = relay.NewNodeDefinitions(relay.NodeDefinitionsConfig{
		IDFetcher: func(id string, info graphql.ResolveInfo) interface{} {
			...
		},
		TypeResolve: func(value interface{}, info graphql.ResolveInfo) *graphql.Object {
			// based on the type of the value, return GraphQLObjectType
			switch value.(type) {
			default:
				return testType //Depends on the test.go
			}
		},
	})
}


//root.go
package schema

import (
	"github.com/graphql-go/graphql"
)

var Schema graphql.Schema

func init() {
	queryType := graphql.NewObject(graphql.ObjectConfig{
		Name: "Query",
		Fields: graphql.Fields{
            "version": &graphql.Field{
			     Type: versionType, //Depends on testtype.go
			     ...
		    },
			"node": nodeDefinitions.NodeField, //Depends on node.go
		},
	})

	Schema, _ = graphql.NewSchema(graphql.SchemaConfig{
		Query: queryType,
	})
}

//testtype.go
package schema

import (
	"github.com/graphql-go/graphql"
	"github.com/graphql-go/relay"
)

var testType *graphql.Object

func init() {
	testType = graphql.NewObject(graphql.ObjectConfig{
		...
		Interfaces: []*graphql.Interface{
			nodeDefinitions.NodeInterface, //Depends on node.go
		},
	})
}

I then use the package in main.go:

result := graphql.Do(graphql.Params{
		Schema:        schema.Schema,
		RequestString: r.URL.Query()["query"][0],
	})

While the package builds correctly, it complains with an error when I run it:

panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x1 addr=0x0 pc=0x48e4b6]

goroutine 1 [running]:
test/testproject/vendor/github.com/graphql-go/graphql.(*Object).Error(0x0, 0xc082003380, 0x3c)
        C:/go/src/test/testproject/vendor/github.com/graphql-go/graphql/definition.go:440 +0x26
test/testproject/vendor/github.com/graphql-go/graphql.defineFieldMap(0xda48b0, 0xc08206c780, 0xc0820550e0, 0xda
        C:/go/src/test/testproject/vendor/github.com/graphql-go/graphql/definition.go:498 +0x532
test/testproject/vendor/github.com/graphql-go/graphql.(*Object).Fields(0xc08206c780, 0xc08206c780)
        C:/go/src/test/testproject/vendor/github.com/graphql-go/graphql/definition.go:416 +0x106
test/testproject/vendor/github.com/graphql-go/graphql.typeMapReducer(0xc082055110, 0xda4560, 0xc08206c780, 0x0,
        C:/go/src/test/testproject/vendor/github.com/graphql-go/graphql/schema.go:208 +0x79a
test/testproject/vendor/github.com/graphql-go/graphql.NewSchema(0xc08206c780, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
        C:/go/src/test/testproject/vendor/github.com/graphql-go/graphql/schema.go:67 +0x809
test/testproject/schema.init.2()
        C:/go/src/test/testproject/schema/root.go:37 +0x244
test/testproject/schema.init()
        C:/go/src/test/testproject/schema/version.go:37 +0x5b
main.init()
        C:/go/src/test/testproject/main.go:37 +0x42

This is because:

node.go depends on testtype.go
testtype.go depends on node.go
root.go depends on node.go and testtype.go

go build builds the files in the page by sorting the filenames alphabetically: node.go then root.go then testtype.go.

If I rename root.go to z.go, it builds and runs correctly. Besides renaming root.go to z.go which is less than ideal, is there any other way I can get this working in a scalable way?

答案1

得分: 2

你可以只使用一个init()函数,并将所有内容放在其中。

或者,如果你想继续在多个.go文件中使用多个init()函数,那么创建一个名为init()的“主”init函数,并将其他init函数重命名为initA()initB()等,并按正确的顺序从主init函数中调用这些函数:

func init() {
    initA()
    initB()
}

参考相关问题+答案:https://stackoverflow.com/questions/31650965/what-does-lexical-file-name-order-mean

英文:

You could use just one init() function and put everything in that.

Or if you want to stick with multiple init() functions in multiple .go files, then create one "master" init function that will be called init(), and rename other init functions, e.g. initA(), initB(), and call these from the master init in proper order:

func init() {
    initA()
    initB()
}

See related question+answer: https://stackoverflow.com/questions/31650965/what-does-lexical-file-name-order-mean

huangapple
  • 本文由 发表于 2016年1月28日 13:03:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/35053222.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定