英文:
How can I get an interface{} argument to point to something else?
问题
如何使以下代码工作并输出"Result is: [Value from GetFromMemory]."
?
不幸的是,我不能更改GetItem
和Get
的方法签名。
package main
import "fmt"
type Key string
type Item struct {
Key Key
Value string
}
func GetItem(key Key) interface{} {
return &Item{key, "Value from GetFromMemory"}
}
// 如何使item指向在GetItem中创建的那个?
func Get(key Key, item interface{}) {
item = GetItem(key)
}
func main() {
var item Item
Get("Key1", &item)
// 这应该打印出"Result is: [Value from GetFromMemory]."
fmt.Printf("Result is: [%s].", item.Value)
}
要使代码正常工作并输出期望的结果,您需要将Get
函数的参数item
改为指针类型。这样,您可以在函数内部修改指针指向的值。
以下是修改后的代码:
package main
import "fmt"
type Key string
type Item struct {
Key Key
Value string
}
func GetItem(key Key) interface{} {
return &Item{key, "Value from GetFromMemory"}
}
// 修改Get函数的参数为指针类型
func Get(key Key, item *interface{}) {
*item = GetItem(key)
}
func main() {
var item Item
Get("Key1", &item)
// 这应该打印出"Result is: [Value from GetFromMemory]."
fmt.Printf("Result is: [%s].", item.Value)
}
通过将Get
函数的参数item
改为指针类型,并在函数内部使用解引用操作符*
来修改指针指向的值,您可以使代码正常工作并输出期望的结果。
英文:
How can I make the following work and make the output "Result is: [Value from GetFromMemory]."
?
Unfortunately I cannot change the method signatures of GetItem
and Get
.
http://play.golang.org/p/R5me3Q3y4W
package main
import "fmt"
type Key string
type Item struct {
Key Key
Value string
}
func GetItem(key Key) interface{} {
return &Item{key, "Value from GetFromMemory"}
}
// How can I make item point to the one created in GetItem?
func Get(key Key, item interface{}) {
item = GetItem(key)
}
func main() {
var item Item
Get("Key1", &item)
// This should print "Result is: [Value from GetFromMemory]."
fmt.Printf("Result is: [%s].", item.Value)
}
答案1
得分: 9
由于您正在处理interface{}
值,您可以使用类型断言或反射。
如果您知道要处理的类型,那么类型断言可能是最好的选择(在playground上的代码):
func GetItem(key Key) interface{} {
return &Item{key, "Value from GetFromMemory"}
}
func Get(key Key, item interface{}) {
switch v := item.(type) {
case **Item:
*v = GetItem(key).(*Item)
}
}
// 使用方法:
var item *Item
Get("Key1", &item)
Get
函数的代码布局使您可以轻松添加更多条件来处理其他类型。类型开关检查item
的底层类型。在这种情况下,它是指向指向Item
的指针(在主函数中是*Item
,然后我们给Get
函数传递了&item
的地址,使其成为**Item
)。
在与类型匹配的部分中,我们可以调用GetItem
函数,断言结果对象的类型为*Item
,并将其复制给*v
。
请注意,我将item
变量更改为*Item
,因为您在GetItem
中生成了一个指针值,因此获取指针而不是Item
对象的副本更有意义。
还请注意,您需要检查类型断言的结果,例如从GetItem
中检索值的断言。如果您不这样做,而类型不匹配,比如不是*Item
,您的代码将在运行时发生恐慌。
已检查的类型断言:
v, ok := someInterfaceValue.(SomeType)
// 如果断言成功,ok将为true
为了完整起见,您也可以使用反射来解决您的问题。将Get
定义如下(在playground上的示例):
func Get(key Key, item interface{}) {
itemp := reflect.ValueOf(item).Elem()
itemp.Set(reflect.ValueOf(GetItem(key)))
}
首先,反射获取item
的值(类型为**Item
),并对其进行解引用,假设它是一个指针值,从而得到一个类型为*Item
的反射值。然后,使用Set
方法将该反射值设置为GetItem
的反射值。
当然,您需要检查item
的类型是否实际上是指针。如果不这样做,并且将非指针值传递给Get
,将导致恐慌。
英文:
As you're dealing with interface{}
values you either need type assertions or reflection.
If you know which types you will deal with, type assertions are probably the way to go
(Code on play):
func GetItem(key Key) interface{} {
return &Item{key, "Value from GetFromMemory"}
}
func Get(key Key, item interface{}) {
switch v := item.(type) {
case **Item:
*v = GetItem(key).(*Item)
}
}
// Usage:
var item *Item
Get("Key1", &item)
The code in Get
is laid out so that you can easily add more conditions for several more
types. The type switch checks the underlying type of item
. In this case it is a
pointer to a pointer to an Item
(it was *Item
in main, then we gave Get
the address of &item
, making it a **Item
).
In the section that matches when the type matches, we can then call GetItem
, assert that the resulted object is of type *Item
and copy it to *v
.
Note that I changed the item
variable to *Item
as you're producing a pointer value in GetItem
, so it makes more sense to get the pointer instead of a copy of an Item
object.
Also note that you need to check the result of type assertions like the one used to
retrieve the value from GetItem
. If you don't and the type does not match, say, *Item
,
your code will blow up with a runtime panic.
Checked type assertions:
v, ok := someInterfaceValue.(SomeType)
// ok will be true if the assertion succeeded
For the sake of completeness, you can solve your problem with reflection as well.
Define Get
as follows (Example on play):
func Get(key Key, item interface{}) {
itemp := reflect.ValueOf(item).Elem()
itemp.Set(reflect.ValueOf(GetItem(key)))
}
What happens is that at first the reflected value of item
(type **Item
) is dereferenced,
assuming that it is a pointer value, giving us a reflected value with type *Item
. Said
value is then set with the reflected value of GetItem
by using the Set
method.
Of course you will need to check whether the kind of item
is actually a pointer.
Not doing this and passing a non-pointer value to Get
will result in panics.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论