Pointers 用围棋包装指针

Pointers 用围棋包装指针,pointers,go,dereference,Pointers,Go,Dereference,库foo公开类型A,该库中的函数Fn返回*A 我为a定义了一个名为B的“包装器”: type B foo.A 我是否可以将*A转换为*B,而不取消对A的引用 换句话说,如果我有 a := foo.Fn() // a is a *A b := B(*a) return &b 如何在不使用*a的情况下将*a转换为*b 我询问的原因是,在我使用的库中,github.com/coreos/bbolt,从Open函数返回的*DB值包含一个sync.Mutex,因此当我试图复制互斥体时,编译

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

我为
a
定义了一个名为
B
的“包装器”:

type B foo.A
我是否可以将
*A
转换为
*B
,而不取消对
A
的引用

换句话说,如果我有

a := foo.Fn()   // a is a *A
b := B(*a)
return &b
如何在不使用
*a
的情况下将
*a
转换为
*b

我询问的原因是,在我使用的库中,
github.com/coreos/bbolt
,从
Open
函数返回的
*DB
值包含一个
sync.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数据库。我在模拟这一点时遇到了一个问题,因为
视图
需要一个接受
bolt.Tx
的函数。然后使用该
tx
CreateBucketIfNotExists
中创建一个新的bucket。我无法将该匿名函数参数替换为调用我的hash-map模拟版本的
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.DB
bolt.Tx
替换
Tx
bolt.Bucket
替换
Bucket
。mocker将为所有三种使用底层哈希映射而不是存储到磁盘的类型使用替换。然后,我可以测试我的所有代码,一直到数据库调用。

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

a := foo.Fn()   // a is a *A
b := (*B)(a)
return b
您甚至可以转换函数调用的返回值:

return (*B)(foo.Fn())
试穿一下

这是可能的,因为

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

  • x
    是到
    T

如果下列条件之一适用,则值
x
可分配给类型
T
(“
x
可分配给
T
”):

  • x
    的类型
    V
    T
    相同,并且
    V
    T
    中至少有一个不是类型


*B
*A
类型都没有定义,
*B
的底层类型与
*A
的底层类型相同(这是指向
A
的类型声明中任何类型的底层类型的指针)。

这就是我所寻找的。我尝试了几种组合,但都没有。谢谢。你可以直接转换它们,但奇怪的是,你为什么要首先制作
B
?它不是“包装”
foo.A
,而是删除方法集。我正在尝试为基础数据库编写一个用于单元测试的模拟。不确定这将如何模拟任何内容,因为它仍然需要原始类型。您最好在自己的数据结构中编写所需的类型。请查看我关于如何使用此类型的更新说明。如果你能建议一个更好的方法,我很想听听。我不确定你的意思,你仍然可以用组合类型实现你的接口。这里的基本问题是,基于另一个包中的结构声明一个新类型并不能使您与该包解耦,仍然需要删除所有现有方法,并且需要非常小心地处理复制值。例如(警告,只需在未验证任何内容的情况下键入此内容):