我很难理解如何设置已作为指针传递的接口值。我正在努力实现以下目标:
import "fmt" var Stuff map[string]interface{} func main() { var num int Stuff["key"] = 9001 get("key", &num) fmt.Println("num:", num) } func get(k string, v interface{}) { *v = Stuff[k] }
我要做什么才能使程序输出为
num: 9001
编辑:是否有可能使用所有解决方案reflect?
reflect
您可以使用来模拟AppEngine数据存储接口reflect。通常,我说的是最小化反射,但是您(以及AppEngine和其他ORM)在这里没有其他很好的选择来展示您想要的接口。对于模仿Get您的内容:
Get
reflect.Value
ValueOf()
reflect.Zero
reflect.Field()
reflect.Indirect()
Value.Set()
一个仅通过指针将结构归零的简单示例位于http://play.golang.org/p/g7dNlrG_vr,并在此处复制:
package main import ( "fmt" "reflect" ) func main() { i := 1 clear(&i) fmt.Println(i) } func clear(dst interface{}) { // ValueOf to enter reflect-land dstPtrValue := reflect.ValueOf(dst) // need the type to create a value dstPtrType := dstPtrValue.Type() // *T -> T, crashes if not a ptr dstType := dstPtrType.Elem() // the *dst in *dst = zero dstValue := reflect.Indirect(dstPtrValue) // the zero in *dst = zero zeroValue := reflect.Zero(dstType) // the = in *dst = 0 dstValue.Set(zeroValue) }
为了进行仿真,GetMulti您需要更多的步骤来使用切片。一个示例在http://play.golang.org/p/G_6jit2t-2及以下:
GetMulti
package main import ( "fmt" "reflect" ) func main() { s := []int{} getMultiZeroes(&s, 10) fmt.Println(s) } func getMultiZeroes(slicePtrIface interface{}, howMany int) { // enter `reflect`-land slicePtrValue := reflect.ValueOf(slicePtrIface) // get the type slicePtrType := slicePtrValue.Type() // navigate from `*[]T` to `T` sliceElemType := slicePtrType.Elem().Elem() // crashes if input type not `*[]T` // we'll need this to Append() to sliceValue := reflect.Indirect(slicePtrValue) // and this to Append() sliceElemValue := reflect.Zero(sliceElemType) // append requested number of zeroes for i := 0; i < howMany; i++ { // s := append(s, v) sliceValue.Set(reflect.Append(sliceValue, sliceElemValue)) } }
在实时代码中(相对于像您那样进行测试),使用类型开关(如Martin所建议的)会更快,以便为每种类型运行专用的本机代码。如果您在类型上有不同的行为,那也可能会很方便。为一个例子GetMulti是在http://play.golang.org/p/q-9WyUqv6P及以下:
package main import "fmt" func main() { s := []int{} getZeroes(&s) fmt.Println(s) fails := []float32{} getZeroes(&fails) } func getZeroes(slicePtrIface interface{}) { switch sp := slicePtrIface.(type) { case *[]int: (*sp) = append((*sp), 0, 0) case *[]string: (*sp) = append((*sp), "", "") default: panic(fmt.Sprintf("getZeroes: passed type %T, which is not a pointer to a slice of a supported type", slicePtrIface)) } }
您甚至可以将两者微不足道地结合起来。为常见类型编写自定义代码,并reflect在默认情况下调用慢速版本。在http://play.golang.org/p/6qw52B7eC3上进行演示(不进行复制,因为这是将上述两者结合在一起的简单方法)。
碰巧还有一个最近的问题],那就是如何使一个值传递给GetMulti,而不是模仿GetMulti自身,如果出现的话。
除了回答这个问题以外,更多的是一般参考
“缺乏通过引用传递”是有用的知识,但也需要一些阐述。Go具有指针,以及其他类型,例如包含指向数据的指针的切片。其中有没有意义“通过引用传递”仅仅是围棋永远不会改变的值参数(int,struct)为指针含蓄。C 参考参数完全做到了这一点:C 在调用方中void f(i int&) { i++; }发生更改i,而调用方没有在调用站点上显式传递指针。func (i int) { i++ }不。
int
struct
void f(i int&) { i++; }
i
func (i int) { i++ }
在Go中,您可以查看传递给函数调用的类型,并告诉它可以更改哪些数据。使用C ++参考参数或某些语言的“按引用传递”语义, 任何 调用都可能会更改本地变量。您不能不查找声明就知道。
为了避免不必要的数据复制,在slice,字符串,映射,接口和通道值的实现中已经有指针。在这些类型中,指针,切片和映射实际上将允许您通过它们修改数据。同样,像在C ++中一样,Go的this-like接收器参数可以是一个指针,而&调用代码中没有明确的指示。在Russ Cox的godata帖子中。
this
&