接口实体放入 Google Cloud Datastore 失败

Put into Google Cloud Datastore fails for interface entity

我正在学习 Go 中的一些基本概念,因此我正在试验数据层抽象,类似于我在其他编程语言中所做的,我 运行我的以下代码出现以下错误:

Failed to save task: datastore: invalid entity type

代码如下:

package main

import (
    "context"
    "fmt"
    "log"

    "cloud.google.com/go/datastore"
    "github.com/google/uuid"
)

type DatastoreEntity interface {
    Kind() string
    Name() string
}

type Task struct {
    TaskId      string
    Description string
}

func (task *Task) Kind() string {
    return "tasks"
}

func (task *Task) Name() string {
    return task.TaskId
}

func main() {
    task := Task{
        TaskId:      uuid.New().String(),
        Description: "Buy milk",
    }
    SaveEntity(&task)
}

func SaveEntity(entity DatastoreEntity) {
    ctx := context.Background()
    projectId := "my-gcp-project"
    client, err := datastore.NewClient(ctx, projectId)
    if err != nil {
        log.Fatalf("Failed to create client: %v", err)
    }

    entityKey := datastore.NameKey(entity.Kind(), entity.Name(), nil)

    if _, err := client.Put(ctx, entityKey, &entity); err != nil {
        log.Fatalf("Failed to save task: %v", err)
    }

    fmt.Printf("Saved %v: %v\n", entityKey, entity.Name())
}

如果能帮助我解释为什么这不起作用,我们将不胜感激。

我的第二个问题是,在官方datastore Go package documentation中是这样说的:

// Create a datastore client. In a typical application, you would create
// a single client which is reused for every datastore operation.
dsClient, err := datastore.NewClient(ctx, "my-project")
if err != nil {
    // Handle error.
}

在一个应用程序中只实例化一个 dsClient 一次的推荐模式是什么?

Client.Put() 上的文档非常清楚:

Put saves the entity src into the datastore with the given key. src must be a struct pointer or implement PropertyLoadSaver.

您既不传递结构指针也不传递 PropertyLoadSaver。您传递一个指向接口类型的指针(如果使用的话,您应该很少使用)。在 Go 中,接口有点像 "wrapper" 类型,它可以包装一个具体的值及其类型,其中包装的值也可以是一个指针。所以如果需要一个指针,指针被包装在接口中,所以不需要使用指向接口本身的指针。在某些情况下,它仍然是必需的或有用的,但这种情况很少见。在你遇到需要它之前,避免它。一个例子可能是当你需要接口类型的反射类型描述符时,参见 .

由于您使用 *Task 作为 entity(指向结构的指针),只需使用 entity 而不是 &entity

client.Put(ctx, entityKey, entity)

What is the recommended pattern to instantiate a dsClient only once in an application?

一种方法是使用包级别 ("global") 变量,您可以在其中存储创建一次的 datastore.Client。在任何需要 Client 的地方,只需引用此变量即可。