Golang中验证包含接口指针映射的架构
Golang中验证包含接口指针映射的架构 以下是我想要实现的功能。 一个单一的账本,其类型为:
map[string]interface{}
问题是,每次有人想从账本中读取数据时,都必须将值复制到一个局部变量中,然后对其进行操作。在我的项目中,这种“复制”可能会导致性能问题。
因此,我希望这个映射能持有插入其中的对象的引用。这样,任何使用该映射的人都不需要复制到局部变量,而是可以直接指向原始对象/修改原始对象(允许修改)并完成任务。因此,我将映射结构改为:
map[string]*interface{}
现在的问题是:这种思路正确吗?Go语言是否提供了其他替代工具或机制来实现我想要的功能?
继续,如果我尝试这样做,它会失败:
s:= "some random string"
singleLedger := make(map[string]*interface{})
singleLedger["first_entry"] = &s
哪里出错了? 我想要实现的功能是可能的吗?

Go Playground - The Go Programming Language
更多关于Golang中验证包含接口指针映射的架构的实战教程也可以访问 https://www.itying.com/category-94-b0.html
我猜@Christophe_Meessen,这是在@NobbZ提到之后确保功能的第二种方法。对使用反射持保留态度。
更多关于Golang中验证包含接口指针映射的架构的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
func (l *Ledger) AddElement(key string, value interface{}){
if reflect.ValueOf(value).Kind() != reflect.Ptr {
panic("AddElement accept only a pointer value")
}
// ...
}
谢谢 @NobbZ
NobbZ: 将获取和设置值的操作封装到函数/方法中,并确保通过这些函数只存储指针。
定义会是什么样子?
func (l *Ledger) AddElement(key string, value interface{}){
//如何将接口包装在接口指针内?
}
只需创建一个 map[string]interface{} 类型的映射,并且只存储指针。
将对值的获取和设置操作封装到函数/方法中,并通过这些封装来保证只存储指针。
或者,你也可以将 s 声明为 interface{} 类型,不过我不确定之后是否能重建其原始类型。 https://play.golang.org/p/DIagkFCm_lB
func main() {
fmt.Println("hello world")
}
创建一个展示实现的小例子。然而,它创建的是一个副本对象,而不是指针。 https://play.golang.org/p/AXWNo7X069f
package main
import (
"fmt"
)
type Ledger struct {
kvm map[string]*interface{}
}
func NewLedger() *Ledger {
return &Ledger{kvm: make(map[string]*interface{})}
}
func (l *Ledger) AddToLedger(key string, val *interface{}) {
l.kvm[key] =val
}
func (l *Ledger) ReadFromLedger(key string) *interface{} {
return l.kvm[key]
}
func main() {
s:=NewLedger()
str:=interface{}("some random string")
s.AddToLedger("first",&str)
ledgerPtrInterfaceType:=s.ReadFromLedger("first")
ledgerPtrStringType:=(*ledgerPtrInterfaceType).(string)// is this creating a new 'copy' object?
fmt.Println(ledgerPtrStringType)
str ="updated"
fmt.Println("updated_string:",ledgerPtrStringType)//the string is not updated, what am I missing?
}
在 Go 中,map[string]*interface{} 确实可以存储任意类型的指针,但你的代码失败是因为类型不匹配。&s 的类型是 *string,而映射期望的是 *interface{}。你需要先将值转换为接口类型,再取其指针。
以下是修正后的示例:
package main
import "fmt"
func main() {
s := "some random string"
singleLedger := make(map[string]*interface{})
// 正确方式:先转换为 interface{},再取指针
var i interface{} = s
singleLedger["first_entry"] = &i
// 读取和修改示例
if entry, ok := singleLedger["first_entry"]; ok {
// 通过指针修改值
*entry = "modified string"
fmt.Println(*entry) // 输出: modified string
}
// 存储结构体指针示例
type Data struct {
Value int
}
d := &Data{Value: 42}
singleLedger["struct_entry"] = &d
// 修改结构体字段
if entry, ok := singleLedger["struct_entry"]; ok {
dataPtr := (*entry).(*Data)
dataPtr.Value = 100
fmt.Println(dataPtr.Value) // 输出: 100
}
}
然而,使用 *interface{} 会带来类型断言的开销和复杂性。更常见的做法是直接存储具体类型的指针:
// 使用 map[string]interface{} 存储指针
ledger := make(map[string]interface{})
s := "string"
ledger["str"] = &s
// 修改值
if ptr, ok := ledger["str"].(*string); ok {
*ptr = "new value"
fmt.Println(*ptr) // 输出: new value
}
// 存储结构体指针
type Record struct {
Count int
}
r := &Record{Count: 1}
ledger["record"] = r
// 修改结构体
if rec, ok := ledger["record"].(*Record); ok {
rec.Count = 2
fmt.Println(rec.Count) // 输出: 2
}
如果你需要类型安全,可以考虑使用泛型:
type Ledger[T any] struct {
data map[string]*T
}
func NewLedger[T any]() *Ledger[T] {
return &Ledger[T]{data: make(map[string]*T)}
}
func (l *Ledger[T]) Set(key string, value *T) {
l.data[key] = value
}
func (l *Ledger[T]) Get(key string) (*T, bool) {
val, ok := l.data[key]
return val, ok
}
// 使用示例
func main() {
ledger := NewLedger[string]()
s := "hello"
ledger.Set("test", &s)
if val, ok := ledger.Get("test"); ok {
*val = "world"
fmt.Println(*val) // 输出: world
}
}
对于性能关键场景,直接存储指针确实能避免复制开销,但需要注意并发访问的安全性。如果多个 goroutine 同时访问,需要使用 sync.RWMutex 或 sync.Map 进行保护。

