我理解这个问题,根据答案 here ,但是,我真的可以使用帮助或更详细的代码解释来说明它是如何克服的。
我的情况是这样的:我曾经将模型和 Controller 分开,在我的模型包中我有一个包含所有模型函数接口(interface)的 datastore.go 文件:
package models
type DSDatabase interface {
CreateUser(ctx context.Context, username string, password []byte) (*datastore.Key, error)
// More model functions
}
type datastoreDB struct {
client *datastore.Client
}
var (
DB DSDatabase
_ DSDatabase = &datastoreDB{}
)
func init() {
// init datastore
}
一切都很好,因为模型函数也位于模型包中,所以我在 Controller 包中的函数可以自由调用 models.DB.CreateUser(ctx, "username", []byte("password "))
.
现在,我决定将上述所有代码移动到datastore
包中,而CreateUser
的模型位于user
中包裹。换句话说,package user
现在包含controller和model函数,其中controller相关函数依赖于datastore
包,而DSDatabase
接口(interface)依赖于 user
模型函数。
我真的很感激帮助弄清楚如何克服导入周期,同时保持 DSDatastore
接口(interface)与所有其他包(如 home
和 user
.
如果上面说得不够清楚,上面的代码改为:
package datastore
import (
"github.com/username/projectname/user"
)
type DSDatabase interface {
user.CreateUser(ctx context.Context, username string, passwoUserRegister(ctx context.Context, username string, password []byte) (*datastore.Key, error)
}
...
在我的 user
包中,我在与 Controller 相关的文件中有这个:
package user
import (
"github.com/username/projectname/datastore"
)
func CreateUserPOST(w http.ResponseWriter, r *http.Request) {
// get formdata and such
datastore.DB.CreateUser(ctx, "username", []byte("password"))
}
在另一个与模型相关的文件中我有:
package user
import (
"github.com/username/projectname/datastore"
)
func (db *datastore.datastoreDB) CreateUser(ctx context.Context, username string) (*User, error) {
key := datastore.NameKey("User", username, nil)
var user User
err := db.client.Get(ctx, key, &user)
if err != nil {
return nil, err
}
return &user, nil
}
这当然会导致导入循环,遗憾的是我不知道如何克服......
最佳答案
首先,您不能在 package A 中为 package B 中声明的类型定义方法。
所以这个...
package user
import (
"github.com/username/projectname/datastore"
)
func (db *datastore.datastoreDB) CreateUser(ctx context.Context, username string) (*User, error) {
key := datastore.NameKey("User", username, nil)
var user User
err := db.client.Get(ctx, key, &user)
if err != nil {
return nil, err
}
return &user, nil
}
...甚至不应该编译。
这里...
package datastore
import (
"github.com/username/projectname/user"
)
type DSDatabase interface {
user.CreateUser(ctx context.Context, username string, passwoUserRegister(ctx context.Context, username string, password []byte) (*datastore.Key, error)
}
...这也是无效的 Go 代码。
关于您的问题...您可以做的一件事是在 user
包中定义 Datastore
接口(interface),并将实现放在另一个包中,这有助于当您需要一个接口(interface)的不同实现时,它本身就很好。如果你这样做,你的 user
包就不需要知道 datastore
包了,datastore
包仍然需要知道 >user
包,这没问题。
一个例子:
package user
import (
"context"
)
type DSDatabase interface {
CreateUser(ctx context.Context, username string, password []byte) (*User, error)
// ...
}
// This can be set by the package that implements the interface
// or by any other package that imports the user package and
// a package that defines an implementation of the interface.
var DB DSDatabase
type User struct {
// ...
}
func CreateUserPOST(w http.ResponseWriter, r *http.Request) {
// get formdata and such
DB.CreateUser(ctx, "username", []byte("password"))
}
接口(interface)实现包:
package datastore
import (
"context"
"github.com/username/projectname/user"
)
// DB implements the user.DSDatabase interface.
type DB struct { /* ... */ }
func (db *DB) CreateUser(ctx context.Context, username string) (*user.User, error) {
key := datastore.NameKey("User", username, nil)
var user user.User
err := db.client.Get(ctx, key, &user)
if err != nil {
return nil, err
}
return &user, nil
}
func init() {
// make sure to initialize the user.DB variable that
// is accessed by the CreateUserPOST func or else you'll
// get nil reference panic.
user.DB = &DB{}
}
关于go - 克服 Go 中不允许的导入周期,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43300723/