有没有办法在不使用自定义结构的情况下检索实体?

Is there a way to retrieve an entity without using a custom struct?

结构 datastore.Entity looks very useful, and it's how I want to process entities, but I don't see any API the makes use of it. Most of the functions (such as Get) 采用一个 interface{},只有当结构 精确地 结构类似于传入数据时,它似乎才有效。

// https://godoc.org/cloud.google.com/go/datastore#Client.Get

ctx := context.Background()
client, err := datastore.NewClient(ctx, "project-id")
if err != nil {
    // TODO: Handle error.
}

type Article struct {
    Title       string
    Description string
    Body        string `datastore:",noindex"`
    Author      *datastore.Key
    PublishedAt time.Time
}
key := datastore.NameKey("Article", "articled1", nil)
article := &Article{}
if err := client.Get(ctx, key, article); err != nil {
    // TODO: Handle error.
}

如何以通用方式获得此实体?如果我不完全了解结构怎么办? (更具体地说,我如何获取 datastore.Entity 的实例?)

所以您想要一个可以容纳任何类型实体的 "general" 类型? datastore 包已经为您提供了这样一种类型:datastore.PropertyList.

您可以这样使用它:

var entity datastore.PropertyList
if err := client.Get(ctx, key, &entity); err != nil {
    // TODO: Handle error.
}

来自datastore的相关文档:

Properties

An entity's contents can be represented by a variety of types. These are typically struct pointers, but can also be any type that implements the PropertyLoadSaver interface. If using a struct pointer, you do not have to explicitly implement the PropertyLoadSaver interface; the datastore will automatically convert via reflection. If a struct pointer does implement that interface then those methods will be used in preference to the default behavior for struct pointers. Struct pointers are more strongly typed and are easier to use; PropertyLoadSavers are more flexible.

因此您可以使用任何实现 datastore.PropertyLoadSaver 接口的类型。此接口类型为:

type PropertyLoadSaver interface {
    Load([]Property) error
    Save() ([]Property, error)
}

再次引用 package doc:

The PropertyLoadSaver Interface

An entity's contents can also be represented by any type that implements the PropertyLoadSaver interface. This type may be a struct pointer, but it does not have to be. The datastore package will call Load when getting the entity's contents, and Save when putting the entity's contents. Possible uses include deriving non-stored fields, verifying fields, or indexing a field only if its value is positive.

[...] The *PropertyList type implements PropertyLoadSaver, and can therefore hold an arbitrary entity's contents.