Go:指向接口{}的指针丢失底层类型

时间:2014-11-16 18:02:59

标签: json pointers reflection interface go

我正在使用Go中的一些“通用”函数,这些函数在interface{}上运行并在频道周围发送内容等。减肥,让我说我有类似的东西:

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)
}

输出:

2014/11/16 12:41:44 MyType 
2014/11/16 12:41:44 *interface {}

后跟默认的json.Marshal输出,而不是自定义输出。据我所知,这是因为对Marshal的调用看到了一个指向接口的类型的值而不是指向MyType的指针。

为什么在我&v时会丢失类型信息?我希望输出的第二行是*MyType而不是*interface {}

有没有办法让我在没有显式转换的情况下调用自定义JSON Marshaller?

2 个答案:

答案 0 :(得分:1)

只需将指针传递给结构,而不是传递给函数的值。指针仍为interface{},但指向界面的指针毫无意义。

答案 1 :(得分:0)

听起来您希望在chan interface{}上发送非指针值,并使自定义MarshalJSON方法按预期工作。在这种情况下,只是不要在指针类型上定义方法。

请参阅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)
}

唯一真正的区别是方法接收器。 func (m MyType) MarshalJSON ([]byte, error)代替func (m *MyType) MarshalJSON ([]byte, error)