Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/vue.js/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Go Can';类型为接口{}的结构的t set字段_Go_Go Reflect - Fatal编程技术网

Go Can';类型为接口{}的结构的t set字段

Go Can';类型为接口{}的结构的t set字段,go,go-reflect,Go,Go Reflect,我一直在为reflect软件包苦苦挣扎。下面的代码符合我的期望: package main import ( "reflect" "log" ) type Car struct { Model string } type Person struct { Name string Cars []Car } func ModifyIt(parent interface{},fieldName string, val interface{}) { slice := refle

我一直在为reflect软件包苦苦挣扎。下面的代码符合我的期望:

package main

import (
  "reflect"
  "log"
)
type Car struct {
  Model string
}
type Person struct {
  Name string
  Cars []Car
}

func ModifyIt(parent interface{},fieldName string, val interface{}) {
  slice := reflect.ValueOf(parent).Elem()
  nth := slice.Index(0)
  //row := nth.Interface() // this line causes errors
  row := nth.Interface().(Person)
  elem := reflect.ValueOf(&row).Elem()
  field := elem.FieldByName(fieldName)
  log.Println(field.CanSet())

}

func main() {

  p := []Person{Person{Name:"john"}}
  c := []Car{Car{"corolla"},Car{"jetta"}}

  ModifyIt(&p,"Cars",&c)
}
但是,如果我将行
行:=n.Interface()(Person)
替换为
行:=n.Interface()
,也就是说,我删除了类型断言,那么我会得到错误:

panic:reflect:对接口值调用reflect.Value.FieldByName 在线“字段:=元素FieldByName(fieldName)

在过去的几个小时里,我尝试了很多其他的事情,比如尝试在一些其他变量上执行
reflect.TypeOf()
reflect.Indirect()
等等,但没有成功

我读过一些其他类似的问题:

他们似乎暗示我对指针或接口的工作方式没有很好的理解

所以我的问题是,当结构被类型化为接口时,如何设置结构的字段


更新


我发布了一个解决方案作为答案,但我对它是否是正确或安全的做事方式没有信心。我希望有人能解释,或发布一个更好的解决方案。

纯粹是运气使然,我终于找到了工作

我拼凑了一大堆随机阅读的东西,几乎没有什么押韵或理由。我甚至尝试在Golang网站上阅读反射定律,但我认为我没有很好地理解为什么我不能将变量类型设置为
接口{}
。总的来说,我仍然不明白我做了什么

我下面的解决方案充斥着评论,表明我的困惑,以及对我是否正确或安全地做事缺乏信心

package main

import (
  "reflect"
  "log"
)
type Car struct {
  Model string
}
type Person struct {
  Name string
  Cars []Car
}

func ModifyIt(parent interface{},fieldName string, val interface{}) {
  log.Println(parent)
  slice := reflect.ValueOf(parent).Elem()
  nth := slice.Index(0)
  row := nth.Interface()
  log.Println(nth.CanSet()) // I can set this nth item

  // I think I have a to make a copy, don't fully understand why this is necessary
  newitem := reflect.New(reflect.ValueOf(row).Type())
  newelem := newitem.Elem()
  field := newelem.FieldByName(fieldName)

  // I need to copy the values over from the old nth row to this new item
  for c:=0; c<nth.NumField(); c++ {
    newelem.Field(c).Set(reflect.Indirect(nth.Field(c)))
  }

  // now I can finally set the field for some reason I don't understand
  field.Set(reflect.ValueOf(val).Elem())

  // now that newitem has new contents in the field object, I need to overwrite the nth item with new item
  // I don't know why I'm doing it, but I'll do it
  // I also don't fully understand why I have to use Indirect sometimes, and not other times...it seems interchangeable with ValueOf(something).Elem(), I'm confused....
  nth.Set(reflect.Indirect(newitem))

}

func main() {

  p := []Person{Person{Name:"john"}}
  c := []Car{Car{"corolla"},Car{"jetta"}}

  ModifyIt(&p,"Cars",&c)
  // now parent is up to date, although I have no idea how I got here.
  log.Println(p)
}
主程序包
进口(
“反映”
“日志”
)
类型汽车结构{
模型串
}
类型Person结构{
名称字符串
汽车
}
func ModifyIt(父接口{},字段名字符串,val接口{}){
log.Println(父级)
切片:=reflect.ValueOf(parent.Elem())
n:=切片索引(0)
行:=n.Interface()
log.Println(n.CanSet())//我可以设置第n项
//我想我必须要复印一份,我不完全明白为什么这是必要的
newitem:=reflect.New(reflect.ValueOf(row.Type())
newelem:=newitem.Elem()
字段:=newelem.FieldByName(fieldName)
//我需要将值从旧的第n行复制到此新项
对于c:=0;c请尝试以下方法:

func ModifyIt(slice interface{}, fieldName string, newVal interface{}) {
    // Create a value for the slice.
    v := reflect.ValueOf(slice)

    // Get the first element of the slice.
    e := v.Index(0)

    // Get the field of the slice element that we want to set.
    f := e.FieldByName(fieldName)

    // Set the value!
    f.Set(reflect.ValueOf(newVal))
}
可以这样称呼:

p := []Person{Person{Name: "john"}}
c := []Car{Car{"corolla"}, Car{"jetta"}}
ModifyIt(p, "Cars", c)
请注意,调用直接传递切片,而不是使用指向切片的指针。不需要这些指针,这会增加额外的复杂性


.

以后,我想在
ModifyIt()
函数中添加一些新元素到
v
main()
函数中的变量
p
将保留
v
所拥有的任何值,直到我调用
v=append(v,Person{Name:“Sara”})之前的行。
如果我想
main()中的
p
显示在
ModifyIt()中添加到
v
的新项目
,我是否需要将
p
作为指针传递给
ModifyIt
,然后按照我发布的解决方案进行操作?作为我的评论的后续,我不认为是否将
p
作为指针传递与我最终在
main()中关于
v
append
p
的问题有关
。我需要更多地了解这是如何工作的。我不确定您正在尝试做什么。例如,您想要添加什么?描述您想要添加什么的最佳方式是使用特定类型(汽车、人和这些类型的片段)的代码更新问题。我无法从问题或答案中的代码中导出它。如果要向父切片添加元素,请将指向切片的指针传递给ModifyIt,并将ModifyIt的第一行更改为
v:=reflect.ValueOf(slice.Elem()
。使用
v.Set(reflect.Append(v,newValue))
添加到slice。谢谢,您的建议很有意义,但我仍然在为我刚刚发布的另一个入门级问题挠头