2017-06-28 127 views
2

我有了与该类型接口{}参数,就像一个功能:Golang接口结构

func LoadTemplate(templateData interface{}) { 

在我的情况,templateData是一个结构,但每次它有不同的结构。我使用“interface {}”类型,因为它允许我发送所有类型的数据。

我使用这个templateData将数据发送到模板:

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

但现在我要追加一些新的数据,我不知道该怎么做,因为“接口”型不允许我添加/追加任何东西。

我试图将接口转换为结构,但我不知道如何将数据追加到具有未知结构的结构。

如果我用下面的功能,我可以看到接口的数据:

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)?或者我怎样才能将它转换为一个结构或其他东西来追加新的子/数据?

+0

请张贴的解决方案作为一个答案而不是更新的问题。如果你使用的答案是不同的问题,请举报这个问题为重复的其他问题。如果它不是,它是不同的,请张贴适当详细的解答,以帮助未来的访客,并避免混淆。谢谢。 – Bugs

回答

5

阿德里安是正确的。更进一步,如果您知道实现该接口的类型,则只能对接口执行任何操作。空的界面,interface{}不是真正的“任何”价值,就像通常被误解的那样;它只是一个即时满足所有类型的界面。

因此,只能通过知道添加前后满足空接口的类型,才能从中获取值或创建具有附加值的新“接口”。

在给定静态类型的情况下,最接近你想做什么的是通过将before类型嵌入到after类型中,以便仍然可以在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) 
} 
+1

这些例子帮我解决这个问题。谢谢。 – Pascut

4

您不能将数据任意附加到结构中;它们是静态类型的。您只能将值分配给为特定结构类型定义的字段。你最好的选择可能是使用map而不是结构。

+0

你是对的,谢谢 – Pascut

0

不推荐,但您可以创建动态使用反映封装结构。

下面是一个例子:

包主要

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功能上面shmush任意数量的结构在一起。不幸的是,从documentation

StructOf当前不会生成嵌入字段的包装方法。未来版本中可能会取消此限制。

因此,您创建的结构不会从嵌入类型继承方法。不过,也许它会满足你的需要。