2015-12-14 59 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