Golang :交换两个数字的接口



我想使用接换两个数字,但接口概念对我来说太混乱了。

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() 反映了ab,以便我们可以检查它。在同一行中,我们假设我们有指针值和取消引用他们通过打电话给他们.Elem()

这基本上转化为 ra := *arb := *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的值实际上是指针值,依此类推。我把它省略了澄清的原因。

相关内容

最新更新