Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/go/7.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
Reflection golang通过反射从接口获取结构_Reflection_Go - Fatal编程技术网

Reflection golang通过反射从接口获取结构

Reflection golang通过反射从接口获取结构,reflection,go,Reflection,Go,原始问题: 我正在尝试进行一些反序列化,但我对传入接口时如何访问结构有点困惑 package main import ( "fmt" "reflect" ) type Robot struct { Id int } func f(i interface{}) { v := reflect.ValueOf(i).Elem().FieldByName("Id") fmt.Println("fields: ", reflect.ValueOf(i).Ele

原始问题:

我正在尝试进行一些反序列化,但我对传入接口时如何访问结构有点困惑

package main

import (
    "fmt"
    "reflect"
)

type Robot struct {
    Id int
}

func f(i interface{}) {
    v := reflect.ValueOf(i).Elem().FieldByName("Id")
    fmt.Println("fields: ", reflect.ValueOf(i).Elem().NumField()) 
    ptr := v.Addr().Interface().(*int)
    *ptr = 100
}

func main() {
    robot := Robot{}

    var iface interface{} = robot // if I omit this line and pass in robot this works
    f(&iface)
    fmt.Println(robot.Id) //I want to get here 100

}

如果您只是直接传入结构,那么play示例就可以工作,但是,任何实现特定接口的东西都可以传入(在我的示例中,我只是使用空接口)。然而,我不知道如何将其视为底层结构

更新:

package main

import (
    "fmt"
    "reflect"
)

type MessageOne struct {
    Header   string `FixedWidth:0,4`
    FieldOne string `FixedWidth:"4,4"`
    FieldTwo string `FixedWidth:"8,4"`
}

type MessageTwo struct {
    FieldX string `FixedWidth:"X,Y"`
    FieldY string `FixedWidth:"X,Y"`
}

var (
    messageMap = map[string]interface{}{
        "msg1": MessageOne{FieldOne: "testValueUnchanged"},
        "msg2": MessageTwo{},
    }
)

func deserialize(input string, i interface{}) interface{} {
    value := reflect.ValueOf(i)
    fmt.Println("1st Value Type: ", value.Kind())
    // unswarp ptr
    value = value.Elem()
    fmt.Println("Unwrapped: ", value.Kind())
    value = value.Elem()
    fmt.Println("Unwrapped: ", value.Kind())

    // Create a copy that I can set?
    copyValue := reflect.New(value.Type()).Elem()
    fmt.Println("Orig Struct is settable", value.CanSet())
    fmt.Println("Orig StructField0 is settable", value.Field(0).CanSet())

    fmt.Println("Copy is: ", copyValue.Kind())
    fmt.Println("Copy Struct is settable", copyValue.CanSet())
    fmt.Println("Copy StructField0 is settable", copyValue.Field(0).CanSet())
    fmt.Println("Orig struct type is: ", value.Type())
    fmt.Println("Copy struct type is: ", copyValue.Type())

    copyValue.Field(1).SetString("testValueChanged")

    return copyValue.Interface()
}

func GetMessageFromInput(input string) interface{} {
    selector := input[0:4]
    fmt.Println(selector)
    field := messageMap[selector]
    return deserialize(input, &field)
}

func main() {
    val := messageMap["msg1"]

    serializedData := "msg1.012345678"

    deserializedVal := GetMessageFromInput(serializedData)

    //msg1 := deserializedVal.(MessageOne)

    fmt.Printf("Orig: %+v \nReceived: %+v", val, deserializedVal)
}

我想复制我的结构,从而从这里获得一个可寻址实例:

所以我想我现在的问题是,有没有一种机制可以访问一个可寻址/可设置的结构,而不必求助于副本

根本的问题是获取字符串(实际上是字节数组)并使结构具有有效反序列化所需的信息,而不必编写几十个反序列化函数来维护。因此,这些示例结构中的标记在示例问题中没有提到,但是访问structs标记字段将提供从输入字节填充结构的偏移量。显然,我还没走那么远。我在这里感到沮丧的一部分是,我似乎非常努力地工作,没有走多远,而且我觉得在这个过程中我没有学到多少东西

一些额外的播放编辑让我找回了我的标签:

您不想传递指向接口的指针,而是希望传递指向结构本身的指针

robot := &Robot{}
f(robot)

当您将
robot
分配给
iface
时,您创建了
robot
值的副本。无法从
iface
获取对
robot
的引用


当您传入
f(&iface)
时,对
reflect.ValueOf(i).Elem()
的调用只是返回内部
iface
值,而不是
Robot
结构值。

您可以使用类型断言

value, ok := i(Robot)
if ok {
    fmt.Println(value.Id)
}

在此基础上。

在原始代码中,使用:

var iface interface{} = &robot
f(iface)
解释
在原始版本中,我们正在发送接口变量的地址(它是robot的副本)。这将发送一个类型为interface的指针,因此reflect将在机器人的副本上工作

var iface interface{} = robot
f(&iface)
我们需要做的是,将robot类型的指针分配给接口变量。因此,当我们发送接口时,我们发送的是robot类型的指针,因此reflect与实际的robot对象一起工作,而不是副本

var iface interface{} = &robot
f(iface)

这并不能回答问题。我想知道如何传入接口并访问基础结构。@Gary:如果不传入指针,就无法访问基础结构。再次将其包装到接口中是多余的,因为它在函数调用中被放入
interface{}
。这是如何工作的:74 func Unmarshal(data[]byte,v interface{})错误{@Gary,我猜你指的是json包???,如果你不传入指针,你会得到一个错误:@Gary,指向接口的指针基本上是无用的,而且几乎总是一个错误。指向接口的指针不会给你指向它的值的指针;如果没有指向该结构的指针,你不能修改结构字段。你可以使用反射查找结构上存在的成员的名称并获得对成员的访问权限。由于使用的结构是在中编译的,因此实际上无法获得该结构的实例;相反,您必须使用反射提供的结构属性的接口集。这些接口提供了对读取和设置函数的访问权限ns可以用来操作底层结构(只要它是可修改的)。这基本上就是我正在做的。在“接口{}”中包装纯粹是为了反映我在代码中遇到的问题。我确实找到了解决方法,但go库似乎展示了这种打开接口{}的模式通过接口转换为具体类型。()这个问题措辞拙劣,不能正确反映我遇到的问题(尽管我认为是这样)。我正在更全面地重新创建问题,并边走边阅读json解码部分。感谢大家的输入,准备好后我会发布一个新问题,并在此处放置一个链接。感谢大家的输入。请解释为什么这会帮助用户。添加了解释。