GoNewb
GoNewb

Reputation: 19

Avoiding Go copying interface data

This is part of real world code I'm trying to write. The problem is that Go copies the interface sibling so I can't modify the data. However, if I change to using a pointer to an interface then the concept of equality fails. I know I can use DeapEquals, but not in a map.

package main

import (
    "fmt"
)

type Q interface {
    modify()
}

type P struct {
    name    string
    sibling Q
}

func (x P) modify() {
    x.name = "a"
}

func main() {
    a := P{"a", nil}
    A := P{"?", nil}

    b := P{"b", a}
    B := P{"b", A}

    B.sibling.modify()

    fmt.Println(B)
    fmt.Println(b == B)
}

How do I get Go to let me modify the interface data itself without copying it and modifying the copy?

It seems these are mutually exclusive on a struct:

Upvotes: 1

Views: 490

Answers (2)

Uvelichitel
Uvelichitel

Reputation: 8490

You can use value returned from modify()

package main

import (
    "fmt"
)

type Q interface {
    modify() Q           //See here
}

type P struct {
    name    string
    sibling Q
}

func (x P) modify() Q{    //Here
    x.name = "a"
    return x
}

func main() {
    a := P{"a", nil}
    A := P{"?", nil}

    b := P{"b", a}
    B := P{"b", A}

    B.sibling=B.sibling.modify() //And here

    fmt.Println(B)
    fmt.Println(b == B)
}

It's verbose a bit, but at least works https://play.golang.org/p/8oM90wriN0

Upvotes: 0

IamNaN
IamNaN

Reputation: 6864

The only way to modify the data without copying it is to use pointers.

I'm a little confused by what you are saying as your example uses a struct and you talk about structs but then you say you need to be able to use maps. Either way, DeepReflect works with both. Here is your example modified to use pointers:

package main

import (
    "fmt"
    "reflect"
)

type Q interface {
    modify()
}

type P struct {
    name    string
    sibling Q
}

func (x *P) modify() {
    x.name = "a"
}

func main() {
    a := P{"a", nil}
    A := P{"?", nil}

    b := P{"b", &a}
    B := P{"b", &A}

    B.sibling.modify()

    fmt.Println("a:", a)
    fmt.Println("A:", A)
    fmt.Println("b:", b)
    fmt.Println("B:", B)
    fmt.Println(b == B)
    fmt.Println(reflect.DeepEqual(b, B))
}

Prints:

a: {a <nil>}
A: {a <nil>}
b: {b 0x10436180}
B: {b 0x10436190}
false
true

And you can see this post for doing the same with maps.

Upvotes: 3

Related Questions