Go:指向interface{}的指针丢失了底层类型。

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

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 (
	&quot;encoding/json&quot;
	&quot;fmt&quot;
	&quot;log&quot;
	&quot;time&quot;
)

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(`&quot;%s&quot;`, m.name)), nil
}

func main() {
	ch := make(chan interface{})

	go printer(ch)
	ch &lt;- &quot;string value&quot;
	ch &lt;- 25
	ch &lt;- MyType{
		name: &quot;foo&quot;,
	}

	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)

huangapple
  • 本文由 发表于 2014年11月17日 02:02:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/26960243.html
匿名

发表评论

匿名网友

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

确定