gpt4 book ai didi

戈朗 : interface to swap two numbers

转载 作者:IT王子 更新时间:2023-10-29 01:07:26 27 4
gpt4 key购买 nike

我想使用接口(interface)交换两个数字,但接口(interface)的概念让我很困惑。

http://play.golang.org/p/qhwyxMRj-c

这是代码和 Playground 。如何使用界面并交换两个输入数字?我需要定义两个结构吗?

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{} 类型只是一种接受所有值的类型,因为它是一个具有空方法集的接口(interface),并且每种类型都可以满足这一点。例如,int 没有任何方法,interface{} 也没有。

对于交换两个变量值的方法,您首先需要确保这些变量实际上是可修改的。传递给函数的值总是被复制(除了像 slice 和映射这样的引用类型,但这不是我们目前关心的)。您可以通过使用指向变量的指针来实现可修改的参数。

因此,有了这些知识,您可以继续定义 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() 反射(reflect)了 ab这样我们就可以检查它。在同一行中,我们假设我们有指针值和取消引用他们通过调用 .Elem()在他们身上。

这基本上转换为 ra := *arb := *b。之后,我们通过使用 .Interface() 请求值来制作 *a 的副本。并分配它(有效地制作副本)。

最后,我们使用[ra.Set(rb)] 5a 的值设置为b ,转换为 *a = *b然后将 b 分配给我们存储在 temp 中的 a。变前。为了这,我们需要将 tmp 转换回自身的反射,以便可以使用 rb.Set()(它需要一个 reflect.Value 作为参数)。

我们可以做得更好吗?

是的!我们可以使代码更加类型安全,或者更好的是,使 Swap 的定义类型安全通过使用 reflect.MakeFunc .在文档中(点击链接)是一个非常有用的例子就像你正在尝试的那样。本质上你可以用内容填充函数原型(prototype)通过使用反射。当您提供函数的原型(prototype)(签名)时编译器可以检查类型,当值被缩减为 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 是一样的作为文档中使用的那个,解释得很好。

免责声明:上面的代码对给定的内容做了很多假设,值(value)观是什么样的。通常你需要检查,例如,给定的SwapNum 的值实际上是指针值等等。我把它留给了清晰的原因。

关于戈朗 : interface to swap two numbers,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19301742/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com