Golang:交换两个数字的接口 [英] Golang : interface to swap two numbers

查看:108
本文介绍了Golang:交换两个数字的接口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想用界面交换两个数字,但界面概念对我来说很困惑。

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



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

 类型num结构{
接口{}
}

类型数字结构{
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
}
接口{} type只是一个接受所有值的类型,因为它是一个具有空方法集的接口,每个类型都可以满足这个接口。 int 例如没有任何方法, interface {}



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



因此,有了这些知识,您可以继续并定义 SwapNum >

  func SwapNum(a interface {},b interface {})
SwapNum
是一个接受任何类型的两个参数的函数。$ c $>


$ b


您无法写入

  func SwapNum(a * interface {},b * interface {})

,因为这只会接受类型 * interface {} (自己尝试此处)。



所以我们有一个签名,唯一剩下的就是交换值。

  func SwapNum(a interface {},b interface {}){
* a,* b = * b,* a
}

不,这将不是以这种方式工作。通过使用 interface {} ,我们必须执行运行时类型断言来检查我们是否做对了。所以代码必须使用 reflect 包进行扩展。 这篇文章可能会让你开始,如果你不知道反射。



基本上我们需要这个函数:

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

这段代码反映了 a b ,其中 reflect.ValueOf() ,以便我们可以
检查它。在同一行中,我们假设我们已经获得了指针值并通过调用 <$ c
$ b $ p

这基本上转化为 ra:= * $ c> .Elem() 。 a rb:= * b
在此之后,我们通过使用 * a /#Value.Interface> .Interface()
并赋值(有效复制)。



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



我们可以做更好吗?



是的!我们可以通过使用 Swap 类型安全
的定义/包装/反映/#MakeFunc> reflect.MakeFunc
。在文档中(跟随链接)是一个例子,它非常类似于你正在尝试的
。实质上,你可以使用反射来填充内容为
的函数原型。当您提供函数的原型(签名)时,
编译器可以检查类型,当值减小到 interface {} 时, 。



示例用法:

  var intSwap func(* int, * int)
a,b:= 1,0
makeSwap(& intSwap)
intSwap(& a,& b)
// a现在为0,b现在是1

背后的代码:

< pre $ 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 实际上是指针值等等。我以
清楚的原因将它留下。


I want to swap two numbers using interface but the interface concept is so confusing to me.

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

This is the code and playground. How do I use interface and swap two input numbers? Do I need to define two structures?

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
}

解决方案

First of all, the interface{} type is simply a type which accepts all values as it is an interface with an empty method set and every type can satisfy that. int for example does not have any methods, neither does interface{}.

For a method which swaps the values of two variables you first need to make sure these variables are actually modifiable. Values passed to a function are always copied (except reference types like slices and maps but that is not our concern at the moment). You can achieve modifiable parameter by using a pointer to the variable.

So with that knowledge you can go on and define SwapNum like this:

func SwapNum(a interface{}, b interface{})

Now SwapNum is a function that accepts two parameters of any type. You can't write

func SwapNum(a *interface{}, b *interface{})

as this would only accept parameters of type *interface{} and not just any type. (Try it for yourself here).

So we have a signature, the only thing left is swapping the values.

func SwapNum(a interface{}, b interface{}) {
    *a, *b = *b, *a
}

No, this will not work that way. By using interface{} we must do runtime type assertions to check whether we're doing the right thing or not. So the code must be expanded using the reflect package. This article might get you started if you don't know about reflection.

Basically we will need this function:

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

This code makes a reflection of a and b using reflect.ValueOf() so that we can inspect it. In the same line we're assuming that we've got pointer values and dereference them by calling .Elem() on them.

This basically translates to ra := *a and rb := *b. After that, we're making a copy of *a by requesting the value using .Interface() and assigning it (effectively making a copy).

Finally, we set the value of a to b with [ra.Set(rb)]5, which translates to *a = *b and then assigning b to a, which we stored in the temp. variable before. For this, we need to convert tmp back to a reflection of itself so that rb.Set() can be used (it takes a reflect.Value as parameter).

Can we do better?

Yes! We can make the code more type safe, or better, make the definition of Swap type safe by using reflect.MakeFunc. In the doc (follow the link) is an example which is very like what you're trying. Essentially you can fill a function prototype with content by using reflection. As you supplied the prototype (the signature) of the function the compiler can check the types, which it can't when the value is reduced to interface{}.

Example usage:

var intSwap func(*int, *int)
a,b := 1, 0
makeSwap(&intSwap)
intSwap(&a, &b)
// a is now 0, b is now 1

The code behind this:

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

The code of swap is basically the same as that of SwapNum. makeSwap is the same as the one used in the docs where it is explained pretty well.

Disclaimer: The code above makes a lot of assumptions about what is given and what the values look like. Normally you need to check, for example, that the given values to SwapNum actually are pointer values and so forth. I left that out for reasons of clarity.

这篇关于Golang:交换两个数字的接口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆