New instance of struct from the type at runtime in GO

huangapple go评论91阅读模式
英文:

New instance of struct from the type at runtime in GO

问题

我正在尝试在运行时使用结构体的类型(reflect.TypeOf)创建一个新的结构体实例。我已经在StackOverflow上遵循了这个线程的建议:https://stackoverflow.com/questions/7850140/how-do-you-create-a-new-instance-of-a-struct-from-its-type-at-runtime-in-go。这是我的实现(也可以在http://play.golang.org/p/BtX0d5Ytu8找到):

package main

import (
	"fmt"
	"reflect"
	"encoding/json"
	"bytes"
)

type UserInfo struct {
	Email    string `json:"email"`
	FullName string `json:"name"`
	ID       string `json:"_id"`
}

func main() {
	fmt.Println("Hello, playground")
	db := DBEngine{}
	db.DB = make(map[string][]byte)
	
	db.Register(UserInfo{})

	db.Put("142321", UserInfo{"jdoe@acme.com", "John Doe", "142321"})
	ret := db.Get("142321")
	fmt.Println("TypeOf(ret):", reflect.TypeOf(ret))
	fmt.Println("ValueOf(ret):", reflect.ValueOf(ret))
	fmt.Println("Value:", ret)
}

type DBEngine struct {
	Template interface{}
	DB       map[string][]byte
}

func (db *DBEngine) Register(v interface{}) {
	db.Template = v
}

//Set User defined object
func (db *DBEngine) Put(key string, v interface{}) {
	res, _ := json.Marshal(v)
	db.DB[key] = res
}

//Return user defined object
func (db *DBEngine) Get(key string) interface{} {
	decoder := json.NewDecoder(bytes.NewReader(db.DB[key]))
	fmt.Println("Value []byte:", string(db.DB[key]))
	ret := reflect.New(reflect.TypeOf(db.Template)).Elem()
	fmt.Println(reflect.TypeOf(db.Template), ret)
	decoder.Decode(ret)
	return ret.Interface()
}

由于某种原因,我总是得到一个空的结构体。我无法设置字段或修改它们。有人能够提供一些建议吗?

英文:

I am trying to create new instance of a struct, using it's type (reflect.TypeOf) at runtime. I have followed this thread on StackOverflow https://stackoverflow.com/questions/7850140/how-do-you-create-a-new-instance-of-a-struct-from-its-type-at-runtime-in-go. Here is my implementation (also at http://play.golang.org/p/BtX0d5Ytu8):

package main
import (
"fmt"
"reflect"
"encoding/json"
"bytes"
)
type UserInfo struct {
Email    string `json:"email"`
FullName string `json:"name"`
ID       string `json:"_id"`
}
func main() {
fmt.Println("Hello, playground")
db := DBEngine{}
db.DB = make(map[string][]byte)
db.Register(UserInfo{})
db.Put("142321", UserInfo{"jdoe@acme.com", "John Doe", "142321"})
ret := db.Get("142321")
fmt.Println("TypeOf(ret):", reflect.TypeOf(ret))
fmt.Println("ValueOf(ret):", reflect.ValueOf(ret))
fmt.Println("Value:", ret)
}
type DBEngine struct {
Template interface{}
DB       map[string][]byte
}
func (db *DBEngine) Register(v interface{}) {
db.Template = v
}
//Set User defined object
func (db *DBEngine) Put(key string, v interface{}) {
res, _ := json.Marshal(v)
db.DB[key] = res
}
//Return user defined object
func (db *DBEngine) Get(key string) interface{} {
decoder := json.NewDecoder(bytes.NewReader(db.DB[key]));
fmt.Println("Value []byte:", string(db.DB[key]))
ret := reflect.New(reflect.TypeOf(db.Template)).Elem()
fmt.Println(reflect.TypeOf(db.Template), ret)
decoder.Decode(ret)
return ret.Interface()
}

For some reason, I always get empty struct. I am unable to set fields or modify. Can someone suggest what is wrong?

答案1

得分: 3

我已经审查了你的代码。当你使用反射创建一个类型时,你得到的是一个 Value 类型的值,需要调用 Interface() 方法来获取该新生成值的接口。

请检查以下代码:
http://play.golang.org/p/CHWSV8EG7D

英文:

i reviewed your code. when you new a type with reflect, you got a value in Value type, need to call Interface() to get the interface of that new generated value

check the code
http://play.golang.org/p/CHWSV8EG7D

答案2

得分: 0

在运行reflect.New(sometype)时,会返回一个指向sometype类型的reflect.Value指针。如果使用.Elem(),将会得到一个直接指向空值的reflect.Value。对于main.UserInfo{}来说,可以这样处理。

// 返回用户定义的对象
func (db *DBEngine) Get(key string) interface{} {
    decoder := json.NewDecoder(bytes.NewReader(db.DB[key]))
    fmt.Println("Value []byte:", string(db.DB[key]))
    ret := reflect.New(reflect.TypeOf(db.Template)).Elem() // <-- 错误
    fmt.Println(reflect.TypeOf(db.Template), ret)
    decoder.Decode(ret)
    return ret.Interface()
}
// 打印结果
// Hello, playground
// Value []byte: {"email":"jdoe@acme.com","name":"John Doe","_id":"142321"}
// main.UserInfo {  }
// TypeOf(ret): main.UserInfo
// ValueOf(ret): {  }
// Value: {  }

要获取*sometype的值,请使用.Interface(),这样你就可以进行解码。参考以下代码:

// 返回用户定义的对象
func (db *DBEngine) Get(key string) interface{} {
    decoder := json.NewDecoder(bytes.NewReader(db.DB[key]))
    fmt.Println("Value []byte:", string(db.DB[key]))
    retValue := reflect.New(reflect.TypeOf(db.Template))
    retInter := retValue.Interface() // <--
    fmt.Println(reflect.TypeOf(db.Template), retInter)
    decoder.Decode(retInter)
    return retInter
}

结果:

Hello, playground
Value []byte: {"email":"jdoe@acme.com","name":"John Doe","_id":"142321"}
main.UserInfo &{  }
TypeOf(ret): *main.UserInfo
ValueOf(ret): &{jdoe@acme.com John Doe 142321}
Value: &{jdoe@acme.com John Doe 142321}

在 playground 上查看:https://play.golang.org/p/veTUho5D4d

英文:

On run reflect.New(sometype) result in an pointer for reflect.Value of sometype. If you use .Elem() will get direct value for reflect.Value that is empty. For this main.UserInfo{}.

//Return user defined object
func (db *DBEngine) Get(key string) interface{} {
decoder := json.NewDecoder(bytes.NewReader(db.DB[key]));
fmt.Println(&quot;Value []byte:&quot;, string(db.DB[key]))
ret := reflect.New(reflect.TypeOf(db.Template)).Elem()//&lt;--wrong
fmt.Println(reflect.TypeOf(db.Template), ret)
decoder.Decode(ret)
return ret.Interface()
}
//print
//Hello, playground
//Value []byte: {&quot;email&quot;:&quot;jdoe@acme.com&quot;,&quot;name&quot;:&quot;John Doe&quot;,&quot;_id&quot;:&quot;142321&quot;}
//main.UserInfo {  }
//TypeOf(ret): main.UserInfo
//ValueOf(ret): {  }
//Value: {  }

For get *sometype value use .Interface(), so you will can to decode. See:

//Return user defined object
func (db *DBEngine) Get(key string) interface{} {
decoder := json.NewDecoder(bytes.NewReader(db.DB[key]));
fmt.Println(&quot;Value []byte:&quot;, string(db.DB[key]))
retValue := reflect.New(reflect.TypeOf(db.Template))
retInter := retValue.Interface()//&lt;-- 
fmt.Println(reflect.TypeOf(db.Template), retInter)
decoder.Decode(retInter)
return retInter
}

Result:

Hello, playground
Value []byte: {&quot;email&quot;:&quot;jdoe@acme.com&quot;,&quot;name&quot;:&quot;John Doe&quot;,&quot;_id&quot;:&quot;142321&quot;}
main.UserInfo &amp;{  }
TypeOf(ret): *main.UserInfo
ValueOf(ret): &amp;{jdoe@acme.com John Doe 142321}
Value: &amp;{jdoe@acme.com John Doe 142321}

In playground: https://play.golang.org/p/veTUho5D4d

huangapple
  • 本文由 发表于 2015年11月2日 09:03:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/33469177.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定