克服Go中不允许的导入周期
根据答案,我理解这个问题,但是,我真的需要帮助或更详细的代码解释如何克服它 我的情况是这样的:我以前将模型和控制器分开,在我的模型包中,我有一个datastore.go文件,其中包含所有模型函数的接口:克服Go中不允许的导入周期,go,google-cloud-datastore,Go,Google Cloud Datastore,根据答案,我理解这个问题,但是,我真的需要帮助或更详细的代码解释如何克服它 我的情况是这样的:我以前将模型和控制器分开,在我的模型包中,我有一个datastore.go文件,其中包含所有模型函数的接口: package models type DSDatabase interface { CreateUser(ctx context.Context, username string, password []byte) (*datastore.Key, error) // Mor
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
}
这一切都很好,因为模型函数也位于模型包中,因此控制器包中的我的函数可以自由调用models.DB.CreateUser(ctx,“username”,[]字节(“password”)
现在,我决定将上述所有代码移动到数据存储
包中,而CreateUser
的模型位于user
包中。换句话说,package user
现在同时包含控制器和模型功能,控制器相关功能依赖于datastore
package,而DSDatabase
界面依赖于user
模型功能
我非常感谢您帮助我找出如何克服导入周期,同时将DSDatastore
界面与所有其他软件包(如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)
}
...
在我的用户
软件包中,我的控制器相关文件中有:
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
}
这当然会导致一个导入周期,很遗憾,我不知道如何克服。首先,您不能在包a中定义一个方法,对包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代码
至于你的问题。。。您可以做的一件事是在
用户
包中定义数据存储
接口,并将实现放在另一个包中,这非常适合您在需要一个接口的不同实现时使用。如果您这样做,您的用户
包就不再需要知道数据存储
包,但是数据存储
包仍然需要知道用户
包,这是可以的
例如:
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"))
}
包含接口实现的包:
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{}
}
您似乎在寻找技术解决方案,但实际上您需要更好地定义哪个包使用哪个。使用术语,感觉数据存储是最低级别的,不知道其他包。但我真的说不出你的商业逻辑。另外,在用户包中有一个datastoreDB接收器,感觉很奇怪。也许这个方法应该在数据存储包中?也许代码应该在同一个包中?如果你看一下现实生活中的项目,它们在相同的包中有大量的文件。如果数据存储和用户都需要对方,那么它们就不能是单独的包。为什么它们首先在不同的包中?@alexbt在我使用MVC结构之前,但我喜欢将控制器和模型放在一起的想法。。datastore.go文件还包含创建单个数据存储客户端的配置,然后我可以使用datastoreDB接收器访问该客户端。。但是听起来我需要回去把
用户模型函数
和用户控制器函数
划分成不同的包?@jimb我把它们放在不同的包中,因为我觉得有必要将所有的函数分开(它们彼此无关)在模型
和控制器
包中,建议我将与用户
相关的所有内容放在一起,以避免出现目录:控制器/用户
和模型/用户
,这对我来说是有意义的这回答了你的问题吗?太好了,非常感谢。。但我猜这意味着不可能在用户包中定义CreateUser函数?放弃模型
和控制器
包结构的主要原因是将所有与用户相关的函数放在一个用户包中,但这个解决方案似乎仍然将所有模型函数放在一个数据存储
包中?我非常喜欢在user
包中定义DSDatabase
接口的想法,但是如果不导入datastore
包,这是可能的吗?您可以在用户包中拥有CreateUser funct,但拥有DSDatabase接口似乎毫无意义。您需要它做什么?但是如果我理解正确,通过将CreateUser函数放入user
包中,您需要导入datastore
包(否则您将创建多个datastore客户端),从而导致导入周期错误?我正在开发一个已经相当大的webapp,最后我用特定的前缀命名我的函数,因为所有文件都位于控制器和模型包中,因此,我正在寻找一种方法将其拆分,如果您在user
包中定义CreateUserPOST
和CreateUser
,这很好,您需要额外的数据存储
包做什么?DSDatabase
接口的目的是什么?目的是拥有一个数据存储客户机,我相信要实现这一点,DSDatabase接口是必要的?使用以前的模型
包结构,则与用户
、帖子
等相关的功能可以轻松使用相同的数据存储客户端;但是,如果您的软件包用户
和软件包发布
同时包含控制器和模型功能,如何实现这一点?