Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/go/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
克服Go中不允许的导入周期_Go_Google Cloud Datastore - Fatal编程技术网

克服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

根据答案,我理解这个问题,但是,我真的需要帮助或更详细的代码解释如何克服它

我的情况是这样的:我以前将模型和控制器分开,在我的模型包中,我有一个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
}
这一切都很好,因为模型函数也位于模型包中,因此控制器包中的我的函数可以自由调用
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接口是必要的?使用以前的
模型
包结构,则与
用户
帖子
等相关的功能可以轻松使用相同的数据存储客户端;但是,如果您的
软件包用户
软件包发布
同时包含控制器和模型功能,如何实现这一点?