kudarap
kudarap

Reputation: 781

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

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
}

Upvotes: 21

Views: 27613

Answers (4)

Floating Sunfish
Floating Sunfish

Reputation: 5718

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

Upvotes: 6

Mr_Pink
Mr_Pink

Reputation: 109388

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)

Upvotes: 26

MikeSchinkel
MikeSchinkel

Reputation: 5036

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.

Upvotes: 8

AESTHETICS
AESTHETICS

Reputation: 1049

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

Upvotes: 1

Related Questions