Golang中如何理解和使用*/&whatever操作符

Golang中如何理解和使用*/&whatever操作符 给定以下接口

type Entity interface {
	Key() *datastore.Key
	Uuid() uuid.UUID
	CreatedOn() time.Time
}

这是我想要的:

func NewAccount(uuid uuid.UUID, owner *person.Person, createdOn time.Time) *Account {
	key := datastore.NameKey(KIND, uuid.String(), owner.Key()) //<- 这里报错:"Cannot use 'owner.Key()' (type datastore.Key) as type *Key"
	return &Account{key: key, Owner: *owner, createdOn: createdOn.UTC().Format(time.RFC3339Nano)}
}

但是当我尝试将 ownerKey 传递给 datastore.NameKey 时,它会报错:

“Cannot use ‘owner.Key()’ (type datastore.Key) as type *Key”

我可以通过以下方式让它停止报错:

func NewAccount(uuid uuid.UUID, owner *person.Person, createdOn time.Time) *Account {
	ownerKey := owner.Key()
	key := datastore.NameKey(KIND, uuid.String(), &ownerKey)
	return &Account{key: key, Owner: *owner, createdOn: createdOn.UTC().Format(time.RFC3339Nano)}
}

我已经尝试了所有我能想到的方法,根据我所读到的内容,试图让它停止报错,但我无法通过 ()/&/* 的组合来在 inline 中满足它。

有什么神奇的咒语可以让我在行内进行引用/解引用,而不必使用中间变量吗?

PS:这是在使用 Google Cloud Datastore,它需要 *datastore.Key


更多关于Golang中如何理解和使用*/&whatever操作符的实战教程也可以访问 https://www.itying.com/category-94-b0.html

4 回复

这就是我目前所拥有的,但它仍然不允许我内联那个引用。

func NewKey(p *Person) *datastore.Key {
	if p.Uuid == "" {
		p.Uuid = uuid.NewV5(uuid.Nil, p.Email).String()
	}
	return datastore.NameKey(KIND, p.Uuid, parentKey)
}

更多关于Golang中如何理解和使用*/&whatever操作符的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


我已经尝试了所有我能想到的方法,试图让它不再抱怨我所读到的内容,但我无法让 ()/&/* 的组合在 inline 中满足它。

有什么神奇的咒语可以让它内联地引用/解引用,而不必使用中间变量吗?

我认为你做不到——直接使用中间变量吧。

我猜可能有一些极其巧妙的方法可以让你不必这样做,但 Go 语言通常不鼓励这种做法!

为什么 (*person.Person).Key 返回的是 datastore.Key 而不是 *datastore.Key,既然通常的用法是指针?你能重构 person.Person避免这样做吗?如果不能,你可以将其封装到一个函数中:

func KeyPtrOf(kr interface{ Key() datastore.Key }) *datastore.Key {
    temp := kr.Key()
    return &temp
}

语言规范中关于地址运算符的相关部分在这里

似乎存在一些特殊情况,允许获取字面量的地址以合并分配和初始化,但除了这种特殊情况外,似乎只能获取变量的地址或任何可以从变量派生的内容的地址(例如,切片变量的索引、结构体变量的字段,依此类推)。这并不是规范中明确说明的,但似乎是其要点!

在Go中,datastore.NameKey函数需要*datastore.Key类型的参数,而owner.Key()返回的是datastore.Key值类型。你需要获取返回值的地址,但直接对函数调用结果取地址是不允许的。

以下是几种解决方案:

方案1:使用中间变量(你当前的做法)

ownerKey := owner.Key()
key := datastore.NameKey(KIND, uuid.String(), &ownerKey)

方案2:修改接口方法返回指针 如果可能,修改Entity接口让Key()方法直接返回指针:

type Entity interface {
    Key() *datastore.Key  // 返回指针
    Uuid() uuid.UUID
    CreatedOn() time.Time
}

// 然后在person.Person的实现中:
func (p *Person) Key() *datastore.Key {
    // 返回指针
    return &datastore.Key{...}
}

方案3:创建辅助函数

func keyPtr(k datastore.Key) *datastore.Key {
    return &k
}

// 使用:
key := datastore.NameKey(KIND, uuid.String(), keyPtr(owner.Key()))

方案4:使用匿名函数(单行内联)

key := datastore.NameKey(KIND, uuid.String(), func() *datastore.Key {
    k := owner.Key()
    return &k
}())

方案5:如果datastore包提供了转换函数 检查datastore包是否有类似NewKey或转换函数:

// 假设有这样的函数
key := datastore.NameKey(KIND, uuid.String(), datastore.NewKey(owner.Key()))

方案6:修改Account结构体存储指针 如果Account结构体可以存储*datastore.Key

type Account struct {
    key *datastore.Key
    Owner person.Person
    createdOn string
}

func NewAccount(uuid uuid.UUID, owner *person.Person, createdOn time.Time) *Account {
    ownerKey := owner.Key()
    return &Account{
        key: &ownerKey,
        Owner: *owner,
        createdOn: createdOn.UTC().Format(time.RFC3339Nano),
    }
}

最直接且符合Go习惯的做法是方案1或方案2。方案1最简单,方案2最优雅但需要修改接口定义。在Go中,对函数调用结果直接取地址是不允许的,因为函数返回的是临时值,没有确定的内存地址。

回到顶部