go - 克服 Go 中不允许的导入周期

标签 go google-cloud-datastore

我理解这个问题,根据答案 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)与所有其他包(如 homeuser.


如果上面说得不够清楚,上面的代码改为:

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/

相关文章:

go - 客户端断开连接时如何正确使用 ctx.Done()?

http - 为什么我的 http 请求 header 字段中缺少主机?

go - golang中的int16数字加float64

file - golang模板上传文件如何验证文件为空

python - 使用Python将twitter数据直接发送到Google Cloud数据存储

java - 无法提供 key.p12 文件来连接到 Google Cloud Datastore

google-cloud-datastore - 管理 Google Cloud Datastore 中实体内的嵌套实体列表

python - App Engine - 属性错误 : 'function' object has no attribute 'id'

google-app-engine - golang appengine goon lib 本地内存限制

go - 未导出结构中的导出字段