タイプinterface {}のパラメーターを持つ関数があります。
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)に子を追加する方法はありますか?または、新しい子/データを追加するために、どのように構造体または他の何かに変換できますか?
エイドリアンは正しいです。さらに一歩進んで、インターフェイスを実装する型がわかっている場合にのみ、インターフェイスで何でもできます。空のインターフェイス、interface{}
は、一般的に誤解されているような「何でも」の値ではありません。これは、すべてのタイプがすぐに満足するインターフェイスです。
したがって、値を取得するか、追加の前後に空のインターフェースを満たすタイプを知ることで、値を追加した新しい「インターフェース」を作成することができます。
静的な型付けを考えると、やりたいことを行うのに最も近いのは、前の型を後の型に埋め込むことです。これにより、後の型のルートですべてにアクセスできます。以下にこれを示します。
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
を使用することをお勧めします。
推奨されていませんが、reflectパッケージを使用して構造体を動的に作成できます。
以下に例を示します。
パッケージメイン
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
関数のようなものを使用して、任意の数の構造体を一緒にシュムッシュできます。残念ながら、 documentation から:
StructOfは現在、埋め込みフィールドのラッパーメソッドを生成しません。この制限は、将来のバージョンで解除される可能性があります。
したがって、作成された構造体は、埋め込み型からメソッドを継承しません。それでも、多分それはあなたが必要とすることをします。
インターフェイスを構造体に変換するだけの場合は、このメソッドを使用します。
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
}