【问题标题】:Go: Pointer to interface{} loses underyling typeGo:指向 interface{} 的指针丢失了下标类型
【发布时间】:2015-01-13 15:07:27
【问题描述】:

我正在使用 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?

【问题讨论】:

    标签: json pointers reflection interface go


    【解决方案1】:

    只需将指针传递给您的结构,而不是将其值传递给函数。指针仍然是interface{},但指向接口的指针是没有意义的。

    【讨论】:

    • 在我的实际代码中,interface{} 对象通过通道进入,所以我不想发送指针。我想保留通道的按值传递语义,以减少并发错误的可能性。
    • 您可以将通道作为值传递并仍然在它们上发送/接收。
    • 接口值实际上是(类型,指针)对(不会复制大结构),通道值实际上是指向处理通信的真实结构的指针。您可以毫无问题地将两者都作为值传递。见Russ Cox's blog post describing interface valuesthis answer on pointers versus values generally
    【解决方案2】:

    听起来您想通过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)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-04-04
      • 1970-01-01
      • 2015-12-08
      • 2016-12-23
      • 2021-01-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多