Golang中结构体与接口类型的解析与应用
Golang中结构体与接口类型的解析与应用 你好,
我在某个问题上有点卡住了,这个问题在网上看起来是合乎逻辑的,但我在家尝试时却无法让它正常工作。我创建了一个结构体,并将其传递给一个方法:
user := grinch.User{
Username: “lucas”,
}
p := reflect.ValueOf(&user) // 注意:获取 x 的地址。
fmt.Println(“type of p:”, p.Type())
fmt.Println(“settability of p:”, p.CanSet())
v := p.Elem()
fmt.Println(“settability of v:”, v.CanSet())
grinchDb.Where(&user)
当我检查类型时,它是 *grinch.User,到目前为止一切正常。但是当我在 Where 方法中检查时,类型的值变成了 *interface {},我大概能猜到原因,但当我寻找关于这个主题的帮助时,到处都写着 Go 应该记住原始类型并因此显示 *grinch.User,但它没有这样做。
也许我的代码哪里出错了,这是 Where 方法:
func (g *Grinch) Where(obj interface{}) {
p := reflect.ValueOf(&obj) // 注意:获取 x 的地址。
fmt.Println(“type of p:”, p.Type())
fmt.Println(“settability of p:”, p.CanSet())
v := p.Elem()
fmt.Println(“settability of v:”, v.CanSet())
}
有人能看出我这里做错了什么吗?
更多关于Golang中结构体与接口类型的解析与应用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
非常感谢,我为此困扰了好几个小时,却没有注意到那个小小的 & 符号。
更多关于Golang中结构体与接口类型的解析与应用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
你好,@lucas_tambarin,
请移除你 (*Grinch).Where 函数中 p := reflect.ValueOf(&obj) 里的 & 符号。这是在获取 obj 参数的地址,而不是你传入的值。
问题出在 Where 方法中对反射的使用。当你传递 &user 给 Where 方法时,参数 obj 已经是接口类型,而 &obj 获取的是这个接口变量的地址,而不是原始结构体的地址。
以下是修正后的代码:
// 调用方
user := grinch.User{
Username: "lucas",
}
grinchDb.Where(&user)
// Where 方法
func (g *Grinch) Where(obj interface{}) {
// 直接使用 obj 进行反射,不需要再取地址
p := reflect.ValueOf(obj)
fmt.Println("type of p:", p.Type())
fmt.Println("settability of p:", p.CanSet())
// 如果需要修改值,需要获取指针指向的元素
if p.Kind() == reflect.Ptr {
v := p.Elem()
fmt.Println("type of v:", v.Type())
fmt.Println("settability of v:", v.CanSet())
}
}
输出会是:
type of p: *grinch.User
settability of p: false
type of v: grinch.User
settability of v: true
关键点:
obj已经是接口类型,包含了指向*grinch.User的指针reflect.ValueOf(&obj)获取的是接口变量本身的地址,类型为*interface {}- 应该直接使用
reflect.ValueOf(obj)来获取接口中存储的值
如果需要修改结构体字段,可以这样操作:
func (g *Grinch) Where(obj interface{}) {
v := reflect.ValueOf(obj)
if v.Kind() == reflect.Ptr && !v.IsNil() {
elem := v.Elem()
if elem.Kind() == reflect.Struct {
// 可以修改结构体字段
if field := elem.FieldByName("Username"); field.IsValid() && field.CanSet() {
if field.Kind() == reflect.String {
field.SetString("modified")
}
}
}
}
}

