在 Go 中换行指针



foo公开类型A的库,该库中Fn的函数返回*A

我为A定义了一个名为B的"包装器":

type B foo.A

我可以在不取消引用A的情况下将*A转换为*B吗?

换句话说,如果我有

a := foo.Fn()   // a is a *A
b := B(*a)
return &b

如何在不使用*a的情况下将*a转换为*b

我问的原因是,在我正在使用的库中,github.com/coreos/bbolt,从Open函数返回的*DB值包括一个sync.Mutex,因此当我尝试复制Mutex时,编译器会抱怨。

更新以解释我将如何使用它

我有一个

type Datastore struct {
*bolt.DB
}

我还有一个函数(众多函数之一),如下所示:

func (ds *Datastore) ReadOne(bucket, id string, data interface{}) error {
return ds.View(func(tx *bolt.Tx) error {
b, err := tx.CreateBucketIfNotExists([]byte(bucket))
if err != nil {
return fmt.Errorf("opening bucket %s: %v", bucket, err)
}
bytes := b.Get([]byte(id))
if bytes == nil {
return fmt.Errorf("id %s not found", id)
}
if err := json.Unmarshal(bytes, data); err != nil {
return fmt.Errorf("unmarshalling item: %v", err)
}
return nil
})
}

我想使用哈希映射模拟底层 BoltDB 数据库。我在嘲笑这个问题时遇到了一个问题,因为View期望一个需要bolt.Tx的功能。然后,该tx用于在CreateBucketIfNotExists中创建新存储桶。我不能用调用我的哈希映射模拟版本的CreateBucketIfNotExists替换该匿名函数参数。

我想出了这个:

package boltdb
import (
"github.com/coreos/bbolt"
)
type (
bucket bolt.Bucket
// Bucket is a wrapper for bolt.Bucket to facilitate mocking.
Bucket interface {
ForEach(fn func([]byte, []byte) error) error
Get(key []byte) []byte
NextSequence() (uint64, error)
Put(key, value []byte) error
}
db bolt.DB
// DB is a wrapper for bolt.DB to facilitate mocking.
DB interface {
Close() error
Update(fn func(*Tx) error) error
View(fn func(*Tx) error) error
}
transaction bolt.Tx
// Tx is a wrapper for bolt.Tx to facilitate mocking.
Tx interface {
CreateBucketIfNotExists(name []byte) (Bucket, error)
}
)
// ForEach executes a function for each key/value pair in a bucket.
func (b *bucket) ForEach(fn func([]byte, []byte) error) error {
return ((*bolt.Bucket)(b)).ForEach(fn)
}
// Get retrieves the value for a key in the bucket.
func (b *bucket) Get(key []byte) []byte {
return ((*bolt.Bucket)(b)).Get(key)
}
// NextSequence returns an autoincrementing integer for the bucket.
func (b *bucket) NextSequence() (uint64, error) {
return ((*bolt.Bucket)(b)).NextSequence()
}
// Put sets the value for a key in the bucket.
func (b *bucket) Put(key, value []byte) error {
return ((*bolt.Bucket)(b)).Put(key, value)
}
// Close releases all database resources.
func (db *db) Close() error {
return ((*bolt.DB)(db)).Close()
}
// Update executes a function within the context of a read-write managed transaction.
func (db *db) Update(fn func(Tx) error) error {
return ((*bolt.DB)(db)).Update(func(tx *bolt.Tx) error {
t := transaction(*tx)
return fn(&t)
})
}
// View executes a function within the context of a managed read-only transaction.
func (db *db) View(fn func(Tx) error) error {
return ((*bolt.DB)(db)).View(func(tx *bolt.Tx) error {
t := transaction(*tx)
return fn(&t)
})
}
// CreateBucketIfNotExists creates a new bucket if it doesn't already exist.
func (tx *transaction) CreateBucketIfNotExists(name []byte) (Bucket, error) {
b, err := ((*bolt.Tx)(tx)).CreateBucketIfNotExists(name)
if err != nil {
return nil, err
}
w := bucket(*b)
return &w, nil
}

到目前为止,在我的代码中,我只使用上面显示的函数。如果需要新代码,我可以添加更多。

我将在实际代码中用DB替换每个bolt.DBbolt.TxTx替换,bolt.BucketBucket替换。模拟程序将使用所有三种类型的替换,这些类型使用基础哈希映射而不是存储到磁盘。然后,我可以测试我的所有代码,直到数据库调用。

您可以简单/直接将类型*A的值转换为类型为*B的值,只需将*B括起来:

a := foo.Fn()   // a is a *A
b := (*B)(a)
return b

您甚至可以转换函数调用的返回值:

return (*B)(foo.Fn())

在Go Playground上尝试一下。

这是可能的,因为规范:转换:

在以下任何一种情况下,可以将非常量值x转换为类型T

  • x可分配给T

和规格:可分配性:

如果满足以下条件之一,则值x可分配给类型为T的变量("x可分配给T"):

  • x的类型VT具有相同的基础类型,并且至少有一个VT不是定义的类型。

*B*A类型都没有定义,并且*B的基础类型与*A的基础类型相同(它是指向A类型声明中任何类型的基础类型的指针)。

相关内容

  • 没有找到相关文章

最新更新