如何在自定义类型中使用Go泛型?字段访问报错解惑
Go泛型类型断言后无法访问字段的问题解析
问题描述
我对泛型的规则感到十分困惑,想要编写一个可接收多种自定义类型、并针对每种类型执行不同逻辑的函数。我的代码如下:
type myObjOne struct { myfield string } type myObjTwo struct { myObjTwo myOtherField string } type Generic interface { myObjOne | myObjTwo } func derp[T Generic](c T) { switch any(c).(type) { case myObjOne: // 无法像这样访问类型的字段 c.myfield = "sdfsfsdfdsf" case myObjTwo: c.myOtherField = "sdfsfsdfdsf" } return }
为何c.myfield会抛出c.myfield undefined (type T has no field or method myfield) compilerMissingFieldOrMethod错误?
原因分析
你定义的Generic是联合类型约束,它仅说明类型参数T可以是myObjOne或myObjTwo,但编译器不会默认认为T具备这两个类型的字段或方法。
在switch分支里,即便你通过类型断言判断出当前c是myObjOne,但变量c的静态类型依然是T,而非myObjOne。编译阶段编译器只会依据约束Generic检查T的成员,而Generic并没有定义myfield或myOtherField,自然会报错。
解决方法
方法一:断言后使用具体类型变量
在case分支中将c断言为具体类型,赋值给新变量后再访问字段:
func derp[T Generic](c T) { switch v := any(c).(type) { case myObjOne: v.myfield = "sdfsfsdfdsf" // 若要修改原变量,由于v是值拷贝,需要将修改后的v重新赋值给c c = v case myObjTwo: v.myOtherField = "sdfsfsdfdsf" c = v } }
如果是传递指针类型,修改断言后的变量会直接同步到原变量,无需重新赋值:
func derp[T Generic](c *T) { switch v := any(c).(type) { case *myObjOne: v.myfield = "sdfsfsdfdsf" case *myObjTwo: v.myOtherField = "sdfsfsdfdsf" } }
方法二:为约束定义统一方法(更符合泛型设计)
如果不同类型的逻辑可以抽象为统一行为,建议在约束中定义方法签名,让每个类型实现该方法,这样无需类型断言就能处理:
type Generic interface { myObjOne | myObjTwo UpdateField(newVal string) } func (m *myObjOne) UpdateField(newVal string) { m.myfield = newVal } func (m *myObjTwo) UpdateField(newVal string) { m.myOtherField = newVal } func derp[T Generic](c T) { c.UpdateField("sdfsfsdfdsf") }
这种方式更贴合Go泛型的设计初衷,避免了类型断言带来的代码耦合问题。
内容的提问来源于stack exchange,提问作者red888
相关产品推荐
相关产品推荐

