当前位置: 首页 > 面试题库 >

Golang:交换两个数字的接口

羊时铭
2023-03-14
问题内容

我想使用接口交换两个数字,但是接口概念令我感到困惑。

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))
}

该代码反映ab使用reflect.ValueOf()了我们可以对其进行检查的代码。在同一行中,我们假设我们有指针值并通过调用它们来取消引用.Elem()它们。

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

最后,我们使用] 5设置ato 的值,该值转换为
然后分配给,我们将其存储在temp中。变量之前。为此,我们需要转换回自身的反射,以便可以使用它(将a
作为参数)。b``[ra.Set(rb)*a = *b``b``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基本相同SwapNummakeSwap与文档中使用的相同,说明得很好。

免责声明:
上面的代码对给定的值和值的外观进行了许多假设。通常,例如,您需要检查给定的值SwapNum实际上是指针值,依此类推。为了清楚起见,我将其省略。



 类似资料:
  • 问题内容: 我正在尝试了解go的内部原理。考虑以下代码 上面的代码完美地交换了2个数字,a变成5,b变成10。我无法理解它是如何工作的。在第二行代码中考虑,如果将a首先分配给b,则b将为10。现在,如果将b分配给a,那么a也不应也为10。 请帮助我了解它是如何工作的 谢谢 问题答案: TL; DR :反汇编表明CPU必须足够聪明才能看到正在发生的事情,并使用寄存器来避免覆盖内存中的现有值。 这个问

  • 我的代码中有错误。错误是:错误:类SwapNodes是公共的,应该在名为SwapNodes的文件中声明。java公共类SwapNodes{ ^Main.java:104:错误:内部类SwapNodes中的静态声明非法。Main公共静态void Main(String[]args){ ^modifier'static'仅允许在常量变量声明中使用。我的程序如下所示:

  • 我是初学者,我想通过使用两个旧映射hm1和hm2创建一个新映射hm3,在该映射中,我需要第二个映射的值作为键,第一个映射的值作为值,例如:如果映射hm1包含a1作为key1和abc作为value1,它还包含a2作为key2和xyz作为value2,并且还有另一个映射hm2,它包含a1作为key1和b1作为value1,还包含a2作为key2和b2作为value2,那么在映射hm3中,我需要b1作为

  • 问题内容: 我正在尝试编写一个将接受所有数据类型的哈希。一旦进入函数,我将数据作为字节数组处理。我在弄清楚如何将任意类型转换为字节数组时遇到麻烦。 我尝试使用二进制包,但它似乎取决于传入的数据类型。fn (docs)的参数之一需要知道参数的字节顺序。 所有数据类型的大小都是字节的某个倍数(甚至是布尔值),因此理论上这应该很简单。 下面有问题的代码, 问题答案: 代码中的其他问题使我较早离开了软件包

  • 问题内容: 我找不到关于交叉联接的任何信息,包括合并/联接或其他一些东西。我需要使用{my function}作为myfunc处理两个数据帧。相当于: 相当于: 但我需要更有效的解决方案:如果使用了应用,我将如何实现它们; ^^ 问题答案: 对于叉积,请参阅此问题。 本质上,您必须进行常规合并,但为每一行赋予相同的键以进行连接,以使每一行在框架之间相互连接。 然后可以通过应用函数将列添加到新框架:

  • 问题内容: 有什么有效的方法来获取Go中两个切片的交集吗? 我想避免嵌套for循环之类的解决方案 字符串顺序无关紧要 问题答案: 是的,有几种不同的解决方法。.这是一个可以优化的示例。 现在上面定义的交集方法将只运行在的,比如你的例子。您可以在理论上创建一个定义,这个样子的,但是你会依靠反射和类型转换,这样就可以比较,这将增加延迟和使您的代码更难阅读。对于您关心的每种类型,维护和阅读以编写单独的函