我很难理解如何设置已作为指针传递的接口值.我正在尝试按照以下方式完成某些事情:
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]
}
Run Code Online (Sandbox Code Playgroud)
我需要做什么才能使我的程序输出
num: 9001
Run Code Online (Sandbox Code Playgroud)
编辑:是否有可能使用的全能解决方案reflect?
two*_*two 12
您可以使用以下方式模拟AppEngine数据存储区界面reflect; 通常我会说最小化反射,但你(和AppEngine和其他ORM)在这里没有其他很好的选择来呈现你想要的界面.对于模仿Get你的事情:
reflect.Value与ValueOf()reflect.Zeroreflect.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)
}
Run Code Online (Sandbox Code Playgroud)
要进行模拟,GetMulti您需要更多步骤来处理切片.一个例子是http://play.golang.org/p/G_6jit2t-2及以下:
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))
}
}
Run Code Online (Sandbox Code Playgroud)
在实时代码中(与您正在进行的测试相反),使用类型切换(如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))
}
}
Run Code Online (Sandbox Code Playgroud)
你甚至可以轻而易举地将两者结合起来; 编写常见类型的自定义代码,并reflect在默认情况下调用基于慢速的版本.在http://play.golang.org/p/6qw52B7eC3上进行演示(不要复制,因为它是上面两者的简单拼接).
最近发生了另一个关于如何传递值的问题GetMulti,而不是模仿GetMulti自身,如果出现的话.
更多的一般参考,而不是回答这个:
"缺乏参考"是有用的知识,但也需要一些细化.Go有指针,以及其他类型,如包含数据指针的切片.没有"通过引用传递"的意义只是Go永远不会隐式地将值参数(int,struct)更改为指针.C++引用参数就是这样做的:C++ 在调用者中进行了void f(i int&) { i++; }更改i,而调用者没有在调用点显式传入指针.func (i int) { i++ }没有.
在Go中,您可以查看传递给函数调用的类型,并告诉它可以更改哪些数据.使用C++引用参数或某些语言的"按引用传递"语义,任何调用都可能改变本地; 如果不查看声明,你无法分辨.
为了避免不必要的数据复制,在slice,string,map,interface和channel值的实现中已经存在指针.在这些类型中,指针,切片和贴图实际上允许您通过它们修改数据.而且,就像在C++中一样,Go的类似this接收器参数可以是&在调用代码中没有显式的指针.在Russ Cox的godata帖子中有更多关于这一点以及关于何时需要指针的摘要.
在函数调用中,函数值和参数按通常顺序计算.在评估它们之后,调用的参数通过值传递给函数,并且被调用的函数开始执行.当函数返回时,函数的返回参数通过值传递回调用函数.
在Go中,一切都按价值传递; 什么都没有通过引用传递.因此,传递一个指针.例如,
package main
import "fmt"
var Stuff map[string]interface{}
func main() {
Stuff = make(map[string]interface{})
Stuff["key"] = 9001
var value interface{}
get("key", &value)
num := value.(int)
fmt.Println("num:", num)
}
func get(k string, v interface{}) {
*v.(*interface{}) = Stuff[k]
}
Run Code Online (Sandbox Code Playgroud)
输出:
num: 9001