我想使用接换两个数字,但接口概念对我来说太混乱了。
http://play.golang.org/p/qhwyxMRj-c
这是代码和游乐场。 如何使用接口并交换两个输入号码?我需要定义两个结构吗?
type num struct {
value interface{}
}
type numbers struct {
b *num
c *num
}
func (a *num) SwapNum(var1, var2 interface{}) {
var a num
temp := var1
var1 = var2
var2 = temp
}
func main() {
a := 1
b := 2
c := 3.5
d := 5.5
SwapNum(a, b)
fmt.Println(a, b) // 2 1
SwapNum(c, d)
fmt.Println(c, d) // 5.5 3.5
}
首先,interface{}
类型只是一个接受所有值的类型,因为它是一个具有空方法集的接口,每个类型都可以满足这一点。 例如,int
没有任何方法,interface{}
也没有。
对于交换两个变量值的方法,您首先需要确保这些变量实际上是可修改的。传递给函数的值总是被复制的(除了切片和映射等引用类型,但这不是我们目前关心的问题(。可以使用指向变量的指针来实现可修改的参数。
因此,有了这些知识,您就可以继续定义SwapNum
如下:
func SwapNum(a interface{}, b interface{})
现在SwapNum
是一个接受任何类型的两个参数的函数。你不能写
func SwapNum(a *interface{}, b *interface{})
因为这只接受 *interface{}
类型的参数,而不仅仅是任何类型的参数。(在这里亲自尝试一下(。
所以我们有一个签名,唯一剩下的就是交换值。
func SwapNum(a interface{}, b interface{}) {
*a, *b = *b, *a
}
不,这不会那样工作。通过使用interface{}
我们必须执行运行时类型断言来检查我们是否在做正确的事情。因此,必须使用 reflect
包扩展代码。如果您不了解反射,本文可能会帮助您入门。
基本上我们需要这个函数:
func SwapNum(a interface{}, b interface{}) {
ra := reflect.ValueOf(a).Elem()
rb := reflect.ValueOf(b).Elem()
tmp := ra.Interface()
ra.Set(rb)
rb.Set(reflect.ValueOf(tmp))
}
此代码使用 reflect.ValueOf()
反映了a
和b
,以便我们可以检查它。在同一行中,我们假设我们有指针值和取消引用他们通过打电话给他们.Elem()
。
这基本上转化为 ra := *a
和 rb := *b
.之后,我们将通过使用.Interface()
请求值来复制*a
并分配它(有效地制作副本(。
最后,我们将 a
的值设置为 b
[ra.Set(rb)
]5,转换为 *a = *b
然后将b
分配给 a
,我们之前将其存储在 temp. 变量中。为此,我们需要将tmp
转换回自身的反射,以便可以使用rb.Set()
(它采用reflect.Value
作为参数(。
我们能做得更好吗?
是的!我们可以使代码更类型安全,或者更好,使Swap
类型的定义更安全通过使用reflect.MakeFunc
.在文档中(点击链接(是一个非常喜欢你正在尝试的。本质上,您可以用内容填充函数原型通过使用反射。当您提供函数的原型(签名(时编译器可以检查类型,当值减小到interface{}
时,它不能检查类型。
用法示例:
var intSwap func(*int, *int)
a,b := 1, 0
makeSwap(&intSwap)
intSwap(&a, &b)
// a is now 0, b is now 1
这背后的代码:
swap := func(in []reflect.Value) []reflect.Value {
ra := in[0].Elem()
rb := in[1].Elem()
tmp := ra.Interface()
ra.Set(rb)
rb.Set(reflect.ValueOf(tmp))
return nil
}
makeSwap := func(fptr interface{}) {
fn := reflect.ValueOf(fptr).Elem()
v := reflect.MakeFunc(fn.Type(), swap)
fn.Set(v)
}
swap
的代码与SwapNum
的代码基本相同。 makeSwap
是一样的作为文档中使用的一个,它得到了很好的解释。
免责声明:上面的代码对给定的内容和值的外观。通常,您需要检查,例如,给定的要SwapNum
的值实际上是指针值,依此类推。我把它省略了澄清的原因。