如何动态清除结构类型实例的值

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

How to clear values of a instance of a type struct dynamically

问题

使用Go语言是否可以创建一个方法,动态清除结构体实例的值?

type A struct {
    Name  string
    Level int
}

type B struct {
    Skill string
}

func main() {
    a := A{"Momo", 1}
    b := B{"Starfall"}

    // 输出
    // { "Momo", 1}
    // { "Starfall"}

    clear(&a)
    clear(&b)

    // 输出
    // { "", 0}
    // { }
}

func clear(v interface{}) {
    // 一些代码
}

以上代码展示了如何使用Go语言创建一个方法来动态清除结构体实例的值。在main函数中,我们创建了一个类型为AB的结构体实例ab。然后,我们调用clear方法来清除这些实例的值。在clear方法中,你可以编写代码来实现动态清除结构体实例的值的逻辑。

英文:

Is it possible with Go to make a method that dynamically clears the values of a instance of a struct?

type A struct {
	Name string
	Level int
}

type B struct {
	Skill string
}

func main() {
	a := A{"Momo", 1}
	b := B{"Starfall"}
	
	// outputs
	// {"Momo", 1}
	// {"Starfall"}

	clear(a)
	clear(b)

	// outputs
	// { , 0}
	// { }
}

func clear(v interface{}) {
	// some code
}

答案1

得分: 26

你无法在不传递指针的情况下修改原始值。

在你的代码中,更简单和更清晰的方法是直接赋予新的零值。如果你的类型更复杂,你可以用构造函数替换值,或者为你的类型提供带有指针接收器的Reset()方法。

如果你真的想看看如何通过反射来做,你的clear函数可能如下所示:http://play.golang.org/p/g0zIzQA06b

func clear(v interface{}) {
    p := reflect.ValueOf(v).Elem()
    p.Set(reflect.Zero(p.Type()))
}

(如果你传递一个非指针值,这将引发恐慌)

英文:

You can't modify the original values without passing a pointer to them.

It's much easier and more clear to simply assign a new zero value in your code. If your types are more complex, you can replace the values with a constructor, or provide Reset() methods for your types with a pointer receiver.

If you really want to see how to do it via reflection your clear function could look like: http://play.golang.org/p/g0zIzQA06b

func clear(v interface{}) {
    p := reflect.ValueOf(v).Elem()
    p.Set(reflect.Zero(p.Type()))
}

(This will panic if you pass in a non-pointer value)

答案2

得分: 6

尽管这个问题是3年9个月前提出的,但我认为它仍然没有一个好的答案,所以让我提出一个。

没有必要使用反射或者每次想要清除变量时都创建一个新实例。相反,创建一个全新的实例,将其保持在初始的零状态,然后在想要重置变量时,将其复制到对象的内存中。感谢@DaveC指出Reset()方法更符合惯例。

你只需使用指针将零值复制到对象指向的位置。以下代码的意思是:“将zeroA引用的内存的值复制到a引用的内存位置上”:

*a = *zeroA

以下是完整的示例代码,你也可以在Go Playground中尝试运行。(注意,由于Reset()方法的接收者是指向类型A的指针,因此调用Reset()方法可以更新a的值,更新的值在方法调用结束后仍然有效):

package main

import (
    "fmt"
)

type A struct {
    Name  string
    Level int
}

var zeroA = &A{}

func (a *A) Reset() {
    *a = *zeroA
}

func main() {
    a1 := A{"Momo", 1}
    a2 := &a1
    a3 := a1

    fmt.Println(a1)
    fmt.Println(a2)
    fmt.Println(a3)

    a1.Reset()

    fmt.Println(a1)
    fmt.Println(a2)
    fmt.Println(a3)
}

以下是输出结果(注意,我证明了变量被清零,指向该变量的指针也被清零,但如果你对原始变量进行了复制,则不会被清零):

{Momo 1}
&{Momo 1}
{Momo 1}
{ 0}
&{ 0}
{Momo 1}

你也可以使用这种技术来复制包含默认值的结构体的值。然而,请注意这是一种浅拷贝,而不是深拷贝。如果你的结构体包含任何指针属性,这种方法也会复制指针的值,并且不会分配内存来指向值的新副本。因此,如果你想要将结构体重置为新的默认值,包括指向子结构体的指针的副本,你需要在Reset()方法中进行额外的工作。

希望这对其他人有所帮助,这样他们就不必像我一样费了很大的劲才学会这个。

英文:

Even though this question was first asked 3 years and 9 months ago it IMO still does not have a good answer so let me propose one.

There is no need for reflection, or to create a new instance each time you want to clear your variable. Instead create one pristine new instance that you leave in its initial zeroed state which you can then copy over your object's memory when you want to Reset() it. (Hat tip to @DaveC for pointing out that a Reset() method is more idiomatic.)

You simply copy from your zeroed value to the location at which your object points to using pointers. The following reads "Copy the value of the memory that zeroA references to the memory location that a references.":

*a = *zeroA

Here is my full example which you can also try in the Go Playground. (Note that since your receiver for Reset() is a pointer to type A then calling the Reset() method allows you to update the value of a where the update survives past the end of the method call):

package main

import (
    "fmt"
)

type A struct {
    Name string
    Level int
}
var zeroA = &A{}
func (a *A) Reset() {
    *a = *zeroA
}

func main() {
    a1 := A{"Momo", 1}
    a2 := &a1
    a3 := a1

    fmt.Println(a1)
    fmt.Println(a2)
    fmt.Println(a3)

    a1.Reset()

    fmt.Println(a1)
    fmt.Println(a2)
    fmt.Println(a3)
}

And here is your output (Note that I prove that your variable is zeroed out and a pointer to that variable is also zeroed, but if you made a copy of the original it is not zeroed):

{Momo 1}
&{Momo 1}
{Momo 1}
{ 0}
&{ 0}
{Momo 1}	

You can also use this technique to copy over the values of a struct that contains default values. However be aware that this is a shallow copy, not a deep copy. If your struct contains any properties that are pointers this approach will copy the pointer values over too and will not allocate memory to point to new copies of the values pointed to. So you will need to do extra work in Reset() if you want to reset your struct to new defaults, including copies of any sub-structs that are declared with pointers.

I hope this helps others so they do not have to learn this the hard way like it took me.

答案3

得分: 5

你可以将其设置为空结构体,如下所示:

var obj myStruct
obj.field1 = "apple"
obj.field2 = 12

// 重置结构体。
obj = myStruct{}

Playground链接:https://play.golang.org/p/Rf1BqfFe3IQ

英文:

You can just set it to an empty struct like so:

var obj myStruct
obj.field1 = "apple"
obj.field2 = 12

// Reset struct.
obj = myStruct{}

Playground link: https://play.golang.org/p/Rf1BqfFe3IQ

答案4

得分: 1

可以重新分配一个空对象给结构体的值,这样可以重置这些值。

a := A{"Momo", 1}
b := B{"Starfall"}

fmt.Println(a)
fmt.Println(b)
// 输出
// {"Momo", 1}
// {"Starfall"}

a = A{}
b = B{}
// 输出
// { , 0}
// { }

你可以在这个链接上查看代码示例:https://play.golang.org/p/CJ6cx2TFytY

英文:

It's possible to reassign the value with an empty object of the struct which will reset the values.

a := A{"Momo", 1}
b := B{"Starfall"}

fmt.Println(a)
fmt.Println(b)
// outputs
// {"Momo", 1}
// {"Starfall"}

a = A{}
b = B{}
// outputs
// { , 0}
// { }

https://play.golang.org/p/CJ6cx2TFytY

huangapple
  • 本文由 发表于 2015年3月20日 22:28:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/29168905.html
匿名

发表评论

匿名网友

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

确定