簡體   English   中英

Golang接口到struct

[英]Golang interface to struct

我有一個函數,其參數類型為interface {},如下所示:

func LoadTemplate(templateData interface{}) {

在我的例子中,templateData是一個結構,但每次它都有不同的結構。 我使用了“interface {}”類型,因為它允許我發送所有類型的數據。

我正在使用此templateData將數據發送到模板:

err := tmpl.ExecuteTemplate(w, baseTemplateName, templateData)

但是現在我想添加一些新數據,我不知道怎么做,因為“interface”類型不允許我添加/追加任何東西。

我試圖將接口轉換為結構,但我不知道如何將數據附加到具有未知結構的結構。

如果我使用以下函數,我可以看到界面的數據:

templateData = appendAssetsToTemplateData(templateData)

func appendAssetsToTemplateData(t interface{}) interface{} {
    switch reflect.TypeOf(t).Kind() {
    case reflect.Struct:
        fmt.Println("struct")
        s := reflect.ValueOf(t)
        fmt.Println(s)

        //create a new struct based on current interface data
    }

    return t
}

知道如何將子項附加到初始接口參數(templateData)? 或者我如何將其轉換為結構或其他內容以附加新的子/數據?

阿德里安是對的。 更進一步,如果您知道實現該接口的類型,則只能對接口執行任何操作。 空接口, interface{}實際上並不像通常被誤解的“任何”值; 它只是一個立即滿足所有類型的接口。

因此,您只能通過在添加之前和之后知道滿足空接口的類型來從中獲取值或創建具有添加值的新“接口”。

在靜態類型中,最接近你可以做到你想要的是通過在after類型中嵌入before類型,以便仍然可以在after類型的根處訪問所有內容。 以下說明了這一點。

https://play.golang.org/p/JdF7Uevlqp

package main

import (
    "fmt"
)

type Before struct {
    m map[string]string
}

type After struct {
    Before
    s []string
}

func contrivedAfter(b interface{}) interface{} {
    return After{b.(Before), []string{"new value"}}
}

func main() {
    b := Before{map[string]string{"some": "value"}}
    a := contrivedAfter(b).(After)
    fmt.Println(a.m)
    fmt.Println(a.s)
}

此外,由於傳遞給模板的數據不需要您指定類型,因此您可以使用匿名結構來完成非常相似的操作。

https://play.golang.org/p/3KUfHULR84

package main

import (
    "fmt"
)

type Before struct {
    m map[string]string
}

func contrivedAfter(b interface{}) interface{} {
    return struct{
        Before
        s []string
    }{b.(Before), []string{"new value"}}
}

func main() {
    b := Before{map[string]string{"some": "value"}}
    a := contrivedAfter(b)
    fmt.Println(a)
}

您不能隨意將數據附加到結構中; 他們是靜態打字的。 您只能將值分配給為該特定結構類型定義的字段。 你最好的選擇可能是使用map而不是結構。

不推薦,但您可以使用反射包動態創建結構。

這是一個例子:

包主

import (
    "encoding/json"
    "os"
    "reflect"
)

type S struct {
    Name string
}

type D struct {
    Pants bool
}

func main() {
    a := Combine(&S{"Bob"}, &D{true})
    json.NewEncoder(os.Stderr).Encode(a)
}

func Combine(v ...interface{}) interface{} {
    f := make([]reflect.StructField, len(v))
    for i, u := range v {
        f[i].Type = reflect.TypeOf(u)
        f[i].Anonymous = true
    }

    r := reflect.New(reflect.StructOf(f)).Elem()
    for i, u := range v {
        r.Field(i).Set(reflect.ValueOf(u))
    }
    return r.Addr().Interface()
}

您可以使用類似上面的Combine函數來將任意數量的結構組合在一起。 不幸的是,從文檔

StructOf當前不為嵌入字段生成包裝器方法。 在將來的版本中可能會解除此限制。

因此,您創建的結構將不會從嵌入類型繼承方法。 不過,也許它可以滿足您的需求。

如果您只是想將接口轉換為struct,請使用此方法。

type Customer struct {
    Name string `json:"name"`
}

func main() {
    // create a customer, add it to DTO object and marshal it
    receivedData := somefunc() //returns interface

    //Attempt to unmarshall our customer
    receivedCustomer := getCustomerFromDTO(receivedData)
    fmt.Println(receivedCustomer)
}

func getCustomerFromDTO(data interface{}) Customer {
    m := data.(map[string]interface{})
    customer := Customer{}
    if name, ok := m["name"].(string); ok {
        customer.Name = name
    }
    return customer
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM