覆盖接口指针的值

huangapple go评论88阅读模式
英文:

Overwriting an interface pointer value

问题

我创建了一个用于处理结构体值的基本数学运算的接口。该接口的数学函数总是更新结构体指针的值。

我的问题是,在某个时刻,我想要将值重写为初始值,但我只能使用接口进行操作。因为它是一个指针接口(不确定是否是人们所说的),我无法“克隆”结构体的初始值以便稍后进行重写。

请注意,我正在尽力避免使用反射。

以下是我的代码。它可能比我试图解释它更容易理解:

package main

import (
	"fmt"
)

type mather interface {
	add(mather) mather
	sub(mather) mather
}

type float struct {
	value float64
}

func (f *float) add(m mather) mather {
	f.value += m.(*float).value
	return f
}

func (f *float) sub(m mather) mather {
	f.value -= m.(*float).value
	return f
}

func (f *float) get() interface{} {
	return *f
}

func main() {
	var a, b, c mather

	a = &float{2} // this could be any time. approximitly 10 possible types
	b = &float{7} // this could be any time. approximitly 10 possible types

	// float can't be used again below, only mather

	c = a

	fmt.Println(a)
	fmt.Println(b)
	fmt.Println()

	// a's math
	doMath(a)

	// now math is done, we need to reset the value from before the math was done
	// set *a equal to *c. (a == &float{2})
	resetMath(a, c)

	// b's math
	doMath(b)

	// now math is done, we need to reset the value from before the math was done
	// set *b equal to *c. (b == &float{7})
	resetMath(b, c)

	fmt.Println(a)
	fmt.Println(b)

}

func doMath(m mather) {
	m.add(&float{3})
}

func resetMath(m mather, r mather) {
	m = r
}

你可以在这里查看代码:https://play.golang.org/p/3Szk8uQGy5

英文:

I made an interface meant to do basic math with struct values. The interface's math functions always update the values of the struct's pointer.

My problem is that at some point, I want to overwrite the value to the initial value but I only have the interface to work with. Because it is a pointer interface (not 100% sure if this is what people call it), I am unable to "clone" the initial value of the struct in order to overwrite later.

Please also note I'm trying my best to avoid reflection.

Here is my code. Will probably make a lot more sense than me trying to explain it:

package main
import (
"fmt"
)
type mather interface {
add(mather) mather
sub(mather) mather
}
type float struct {
value float64
}
func (f *float) add(m mather) mather {
f.value += m.(*float).value
return f
}
func (f *float) sub(m mather) mather {
f.value -= m.(*float).value
return f
}
func (f *float) get() interface{} {
return *f
}
func main() {
var a, b, c mather
a = &float{2} // this could be any time. approximitly 10 possible types
b = &float{7} // this could be any time. approximitly 10 possible types
// float can't be used again below, only mather
c = a
fmt.Println(a)
fmt.Println(b)
fmt.Println()
// a's math
doMath(a)
// now math is done, we need to reset the value from before the math was done
// set *a equal to *c. (a == &float{2})
resetMath(a, c)
// b's math
doMath(b)
// now math is done, we need to reset the value from before the math was done
// set *b equal to *c. (b == &float{7})
resetMath(b, c)
fmt.Println(a)
fmt.Println(b)
}
func doMath(m mather) {
m.add(&float{3})
}
func resetMath(m mather, r mather) {
m = r
}

https://play.golang.org/p/3Szk8uQGy5

答案1

得分: 2

你需要在mather接口中定义cloneset方法,如下所示:

type mather interface {
    add(mather) mather
    sub(mather) mather
    get() interface{}
    clone() mather
    set(v mather)
}

float类型中getsetclone的实现如下:

func (f *float) get() interface{} {
    return f.value
}

func (f *float) clone() mather {
    return &float{f.value}
}

func (f *float) set(v mather) {
    switch v := v.(type) {
    case *float:
        f.value = v.value
    // 处理其他可能的类型...
    default:
        // 处理未知类型
    }
}

Playground上查看工作示例。唯一复杂的部分是set方法,你需要确定底层类型。在这里,你可以使用类型切换来获取底层类型,然后将其赋值给float。在其他底层类型中也需要添加类似的代码(你提到有10种可能的类型)。

英文:

You need to define clone and set method in mather interface, i.e.:

type mather interface {
add(mather) mather
sub(mather) mather
get() interface{}
clone() mather
set(v mather)
}

The implementation of get, set and clone in float type looks like:

func (f *float) get() interface{} {
return f.value
}
func (f *float) clone() mather {
return &float{f.value}
}
func (f *float) set(v mather) {
switch v := v.(type) {
case *float:
f.value = v.value
//handle other possible types...
default:
//handle unknown types
}
}

See working example in Playground. The only complicated parts is set in which you should determined the underlying type. Here you can use type switch to get underlying type, then assign it to float. Similar codes need to be added in the other underlying types (you mention that there are 10 possible types).

答案2

得分: 1

如果你有底层类型的引用,你可以使用简单的寻址运算符来实现,如果需要,你可以通过类型断言来获取底层类型的引用,而不必使用反射。一旦你有了一个*float,就很容易了:

f := &float{2}
var a, b *float
a = f
b = new(float)
*b = *f        // 将f指向的值赋给b指向的值

在这种情况下,你的局部变量现在是*float而不是mather,但至少在你的示例中这并不重要。如果这很重要,如上所述,你可以使用类型断言。

英文:

You can do it using simple addressing operators if you have a reference of the underlying type, which you can get through type assertion if necessary without having to resort to reflection. Once you have a *float, it's easy:

f := &float{2}
var a, b *float
a = f
b = new(float)
*b = *f        // Assign the value pointed to by f to the value pointed to by b

In this case your local vars are now *float instead of mather, but at least in your example that doesn't matter. If it does matter, as noted above, you can use type assertions.

huangapple
  • 本文由 发表于 2017年7月21日 04:24:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/45224545.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定