【问题标题】:Pointer to interface with saving type指向具有保存类型的接口的指针
【发布时间】:2016-01-04 22:12:32
【问题描述】:

解释我的问题的最短方法是that code

var i interface{} // I can't change it. In fact this is a function,
i = Item{10}      // that receives interface{}, that contain object (not pointer to object!)

fmt.Printf("%T %v\n", i, i)
// fmt.Println(i.(NextValuer).NextVal())  // won't compile
i = &i
fmt.Printf("%T %v\n", i, i)               // there i is pointer to interface{} (not to Item)
// fmt.Println(i.(NextValuer).NextVal())  // panics
// fmt.Println(i.(*NextValuer).NextVal()) // won't compile

但是,如果我尝试将指向 Item 的指针设置为 i,则代码有效:

i = &Item{10}
fmt.Printf("%T %v\n", i, i)
fmt.Println(i.(NextValuer).NextVal())

但我的函数接收对象,而不是指向它的指针。我可以得到它的类型(第一个fmt.Printf)。但是当我尝试指向它时,我收到指向 interface{} 的指针,而不是指向我的对象 (Item) 的指针。

我可以指向这个对象来调用NextVal吗?或者可能是其他方式来做到这一点

【问题讨论】:

  • 这一行没有意义:i = &i
  • 可能是。但stdout 中的前两行不同
  • 这里最好的建议可能是:停止给牦牛剃毛,从头开始重新设计一切。 NextValuer 闻起来像是在 Go 上强制迭代器。如果某件事只是无休止地返回一个又一个,为什么不使用通道呢?
  • @Volker 这只是显示问题的简短版本。真正的代码更大更复杂
  • 然后重新设计似乎更合适。

标签: pointers go interface


【解决方案1】:

永远不要使用指向接口的指针。如果您需要一个指针来调用带有指针接收器的方法,则必须将指针放入interface{}

如果您已经在 interface{} 中有值,您想在其中调用带有指针接收器的方法,则需要制作该值的可寻址副本。

您尝试使用i = &i 完成的可能是:

item := i.(Item)
i = &item

这会创建原始Item 的可寻址副本,然后将指向该副本的指针放入i。请注意,这永远不会改变原始Item 的值。

如果您不知道interface{} 中可以包含的类型,可以使用“reflect”复制该值:

func nextVal(i interface{}) {
    // get the value in i
    v := reflect.ValueOf(i)

    // create a pointer to a new value of the same type as i
    n := reflect.New(v.Type())
    // set the new value with the value of i
    n.Elem().Set(v)

    // Get the new pointer as an interface, and call NextVal
    fmt.Println("NextVal:", n.Interface().(NextValuer).NextVal())

    // this could also be assigned another interface{}
    i = n.Interface()
    nv, ok := i.(NextValuer)
    fmt.Printf("i is a NextValuer: %t\nNextVal: %d\n", ok, nv.NextVal())
}

http://play.golang.org/p/gbO9QGz2Tq

【讨论】:

  • 不,我做不到。因为我有很多类型,所以实现了NextValuer
  • @AlikSend:“不,你做不到”是什么意思?你要么需要从一个指针开始(这是你应该做的),要么创建一个副本来获取一个指针,没有任何其他选择。您想要一个使用反射来创建值的新副本的解决方案吗?
  • @JimBe 我只是想出了一个想法来实现它,但是我必须在整个项目中更改代码。如果可以用reflect 完成,你能告诉我吗?这个决定是因为我已经在这个函数中使用了reflect
  • @AlikSend:添加了一个反射示例,当您完全不知道接口可能包含什么类型并且您需要一个指针而不是值时。
  • 我将您的答案标记为解决方案。但我认为在这种情况下重新设计确实更好。谢谢
猜你喜欢
  • 2019-05-04
  • 1970-01-01
  • 2016-08-01
  • 2013-10-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-06
  • 2014-02-16
相关资源
最近更新 更多