Go接口类型断言产生值拷贝,如何调用原对象的指针方法?
问题:Go语言中双向链表存储值类型时无法修改原对象
我为看板系统实现了如下结构:
type Menu struct { Projects dll.DLL } type Project struct { Title string Lists dll.DLL Labels dll.DLL } type List struct { Title string Cards dll.DLL } func StartMenu() *Menu { return &Menu{ Projects: dll.New(), } } func (m *Menu) AddProject(title string) { project := Project{ Title: title, Lists: dll.New(), } m.Projects.Append(project) } func (p *Project) AddList(title string) { list := List{ Title: title, Cards: dll.New(), } p.Lists.Append(list) }
其中dll.DLL是自定义双向链表工具包,节点值为interface{}类型以实现抽象。
编写测试代码时发现无法修改原对象:
menu := kanban.StartMenu() menu.AddProject("project1") project1, err := menu.Projects.WalkTo(0) if err != nil { log.Println(err) } project1Val := project1.GetVal().(kanban.Project) project1Val.AddList("List 1")
原因是project1.GetVal().(kanban.Project)返回的是Project值的拷贝,调用AddList仅修改拷贝而非原对象。
我尝试为dll.Node新增GetValPtr方法,返回*interface{}类型的节点值指针,但无法直接对*interface{}做类型断言,先解引用再断言仍会得到值拷贝:
project1Val := project1.GetValPtr() proj1 := (*project1Val).(kanban.Project) proj1.AddList("List 1")
请问是否有办法断言指针的底层类型,从而直接调用原对象的方法?
解决方案
1. 存储指针而非值类型(推荐方案)
这是Go中处理此类场景的常规做法,修改AddProject方法,将Project指针存入链表:
func (m *Menu) AddProject(title string) { project := &Project{ // 创建Project指针 Title: title, Lists: dll.New(), } m.Projects.Append(project) }
后续在测试代码中,直接将GetVal()断言为*kanban.Project,调用方法即可直接修改原对象:
project1Val := project1.GetVal().(*kanban.Project) project1Val.AddList("List 1")
2. 若必须存储值类型的替代方案
如果因特殊需求必须存储值类型,你需要调整双向链表的设计:
- 修改链表节点的存储逻辑,让
interface{}存储值的指针而非值本身(本质和方案1一致) - 或者为
dll包新增泛型方法实现类型安全的指针获取:
但这种方式仍要求链表中存储的是指针类型,否则无法获取原对象的指针。// 在dll.Node中新增泛型方法 func (n *Node) GetValAsPtr[T any]() (*T, error) { val, ok := n.GetVal().(*T) if !ok { return nil, fmt.Errorf("value is not of type *%T", *new(T)) } return val, nil }
内容的提问来源于stack exchange,提问作者Anacardo
相关产品推荐
相关产品推荐

