2015-12-14 32 views
2

原题:golang通过反射得到的接口结构

我试图做一些反序列化,我有点困惑如何在传递时的接口访问一个结构。

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 

} 

http://play.golang.org/p/y6UN3KZxRB

该剧例如工作,如果你只是在该结构通过直接,但因为它是可能的事情在于,要通过实现一个特定的接口(在我的例子来说,我只是用空的界面)。但是我无法弄清楚如何将它作为底层的结构对待。

更新时间:

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." 

    deserializedVal := GetMessageFromInput(serializedData) 

    //msg1 := deserializedVal.(MessageOne) 

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

http://play.golang.org/p/Cj9oPPGSLM

我得到了拷贝我的结构,并由此及彼的寻址实例的想法:https://gist.github.com/hvoecking/10772475

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

底层的问题是将字符串(真的是字节数组)和具有必要的信息来有效地反序列化它,而不必编写几十个需要维护的反序列化函数。所以这些示例结构中的标记在示例问题中未得到解决,但访问结构标记字段将提供从输入字节中填充结构的偏移量。显然我还没有那么远。我的一部分挫折是,似乎我努力工作得不到很远,我不觉得我在这个过程中学到了很多东西。

这让我我的标签回一些额外的游戏编辑: http://play.golang.org/p/2DbbWLDKPI

+0

您可以使用反射来查找结构中存在的成员的名称并获得对成员的访问权限。因为正在使用的结构被编译进来,所以你实际上并没有得到结构的实例。相反,您必须使用由反射提供的结构属性的一组接口。这些可以访问读取和设置可用于操纵底层结构的函数(只要它是可修改的)。 – zstewart

+0

这就是我正在做的。 “interface {}”中的包装纯粹是为了反映我在代码中遇到的问题。我确实找到了解决方法,但go库似乎展示了这种通过接口将界面展开为具体类型的模式。 (https://golang.org/src/encoding/json/decode.go?s = 2621:2669#L64) – Gary

+0

这个问题措辞不佳,并没有正确反映我遇到的问题(尽管我认为它确实如此)。我正在努力更全面地重新创建问题,并随时阅读json解码部分。感谢大家的投入,我准备好后会发布一个新问题,并在此处添加链接。感谢大家的意见。 – Gary

回答

3

你不想给一个指针传递到接口,你想在一个指向你的结构本身通过。

robot := &Robot{} 
f(robot) 

http://play.golang.org/p/owv-Y4dnkl

您分配给robotiface时刻,您所创建的robot值的副本。没有办法从iface得到回robot的参考。

当你通过f(&iface)时,调用reflect.ValueOf(i).Elem()只是返回内部iface值,而不是Robot结构值。

+0

这并不回答这个问题。我想知道如何传递接口并访问底层结构。 – Gary

+1

@Gary:如果不传入指针,则无法访问底层结构。将它重新包装在界面中是多余的,因为它被放入函数调用的'interface {}中。 – JimB

+0

这是如何工作的:74 \t func Unmarshal(data [] byte,v interface {})错误{ – Gary