我想使用界面交换两个数字,但界面概念对我来说太混乱了。
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
}
答案 0 :(得分:15)
首先,interface{}
类型只是一个接受所有值的类型,因为它是一个具有空方法集的接口,并且每个类型都可以满足该类型。 int
例如没有任何方法,interface{}
也没有。
对于交换两个变量值的方法,首先需要确保这些变量实际上是可修改的。传递给函数的值总是被复制(除了切片和贴图之类的引用类型,但目前我们不关心这一点)。您可以通过使用指向变量的指针来实现可修改的参数。
因此,凭借这些知识,您可以继续并定义SwapNum
,如下所示:
func SwapNum(a interface{}, b interface{})
现在SwapNum
是一个接受任何类型的两个参数的函数。
你不能写
func SwapNum(a *interface{}, b *interface{})
因为这只接受*interface{}
类型的参数,而不仅仅是任何类型。
(亲自试试here)。
所以我们有一个签名,唯一剩下的就是交换价值。
func SwapNum(a interface{}, b interface{}) {
*a, *b = *b, *a
}
不,这将不以这种方式工作。通过使用interface{}
,我们必须执行运行时类型断言来检查我们是否正在做正确的事情。因此必须使用reflect
包扩展代码。如果您不了解反思,This article可能会帮助您。
基本上我们需要这个功能:
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
] 5将b
的值设置为[ra.Set(rb)
,转换为*a = *b
然后将b
分配给我们存储在temp中的a
。变量之前。为了这,
我们需要将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
实际上是指针值等等。我把它留给了
清晰的原因。