英文:
Go: Pointer to interface{} loses underyling type
问题
我正在使用Go语言中的一些“通用”函数,这些函数在interface{}
上操作并在通道中发送数据等。简化一下,假设我有以下代码:
type MyType struct {
// 字段
}
func (m *MyType) MarshalJSON() ([]byte, error) {
// 自定义的MarshalJSON方法
log.Print("custom JSON marshal")
return []byte("hello"), nil
}
func GenericFunc(v interface{}) {
// 做一些操作...
log.Print(reflect.TypeOf(v))
log.Print(reflect.TypeOf(&v))
b, _ := json.Marshal(&v)
fmt.Println(string(b))
}
func main() {
m := MyType{}
GenericFunc(m)
}
这将输出:
2014/11/16 12:41:44 MyType
2014/11/16 12:41:44 *interface {}
而不是自定义的输出。据我所知,这是因为调用Marshal
时,它看到的是指向接口的指针类型,而不是指向MyType
的指针类型。
为什么当我使用&v
时会丢失类型信息?我期望输出的第二行是*MyType
而不是*interface{}
。
有没有办法在不显式转换的情况下调用自定义的JSON编组方法?
英文:
I'm working with some "generic" functions in Go that operate on interface{}
and send things around channels, etc. Slimmed down, let's say I have something like:
type MyType struct {
// Fields
}
func (m *MyType) MarshalJSON() ([]byte, error) {
// MarshalJSON
log.Print("custom JSON marshal")
return []byte("hello"), nil
}
func GenericFunc(v interface{}) {
// Do things...
log.Print(reflect.TypeOf(v))
log.Print(reflect.TypeOf(&v))
b, _ = json.Marshal(&v)
fmt.Println(string(b))
}
func main() {
m := MyType{}
GenericFunc(m)
}
This outputs:
2014/11/16 12:41:44 MyType
2014/11/16 12:41:44 *interface {}
Followed by the default json.Marshal
output, rather than the custom one. As far as I can tell, that's because the call to Marshal
sees a value of type pointer-to-interface rather than pointer-to-MyType.
Why do I lose type information when I take &v
? I would expect the second line of the output to be *MyType
and not *interface {}
.
Is there any way for me have the custom JSON Marshaller called without explicitly casting?
答案1
得分: 2
只需将指向您的结构体的指针传递给函数,而不是传递其值。指针仍然是interface{}
类型,但指向接口的指针是没有意义的。
英文:
Just pass a pointer to your struct and not its value to the function. The pointer is still interface{}
but a pointer to the interface is meaningless.
答案2
得分: 0
看起来你想要在chan interface{}
上发送非指针值,并且希望自定义的MarshalJSON
方法能够正常工作。在这种情况下,只需不在指针类型上定义该方法。
请参考这里
package main
import (
"encoding/json"
"fmt"
"log"
"time"
)
func printer(in chan interface{}) {
for val := range in {
buf, err := json.Marshal(val)
if err != nil {
log.Println(err.Error())
}
log.Println(string(buf))
}
}
type MyType struct {
name string
}
func (m MyType) MarshalJSON() ([]byte, error) {
return []byte(fmt.Sprintf(`"%s"`, m.name)), nil
}
func main() {
ch := make(chan interface{})
go printer(ch)
ch <- "string value"
ch <- 25
ch <- MyType{
name: "foo",
}
time.Sleep(time.Second)
}
唯一的真正区别是方法的接收者。使用func (m MyType) MarshalJSON ([]byte, error)
而不是func (m *MyType) MarshalJSON ([]byte, error)
。
英文:
It sounds like you want to send non-pointer values over a chan interface{}
and have a custom MarshalJSON
method work as expected. In that case, just don't define the method on the pointer type.
See here
package main
import (
"encoding/json"
"fmt"
"log"
"time"
)
func printer(in chan interface{}) {
for val := range in {
buf, err := json.Marshal(val)
if err != nil {
log.Println(err.Error())
}
log.Println(string(buf))
}
}
type MyType struct {
name string
}
func (m MyType) MarshalJSON() ([]byte, error) {
return []byte(fmt.Sprintf(`"%s"`, m.name)), nil
}
func main() {
ch := make(chan interface{})
go printer(ch)
ch <- "string value"
ch <- 25
ch <- MyType{
name: "foo",
}
time.Sleep(time.Second)
}
The only real difference is the method receiver. func (m MyType) MarshalJSON ([]byte, error)
instead of func (m *MyType) MarshalJSON ([]byte, error)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论