避免复制Go接口数据

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

Avoiding Go copying interface data

问题

这是我正在尝试编写的真实世界代码的一部分。问题是Go会复制接口sibling,所以我无法修改数据。然而,如果我改用指向接口的指针,那么相等性的概念就会失败。我知道我可以使用DeepEquals,但不能在map中使用。

我如何让Go允许我修改接口数据本身而不是复制并修改它?

在结构体上,似乎这两个需求是互斥的:

  • 我需要能够使用map
  • 我需要能够使用方法修改接口数据
英文:

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:

  • I need to be able to use maps
  • I need to be able to modify the interface data with methods

答案1

得分: 3

修改数据而不复制它的唯一方法是使用指针。

我对你的说法有点困惑,因为你的示例使用了结构体,并且你谈论了结构体,但是你又说你需要能够使用映射。无论哪种方式,DeepReflect都可以使用。这里是修改后使用指针的示例:

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

输出结果为:

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

你可以查看这篇帖子了解如何在映射中进行相同的操作。

英文:

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 (
	&quot;fmt&quot;
	&quot;reflect&quot;
)

type Q interface {
	modify()
}

type P struct {
	name    string
	sibling Q
}

func (x *P) modify() {
	x.name = &quot;a&quot;
}

func main() {
	a := P{&quot;a&quot;, nil}
	A := P{&quot;?&quot;, nil}

	b := P{&quot;b&quot;, &amp;a}
	B := P{&quot;b&quot;, &amp;A}

	B.sibling.modify()

	fmt.Println(&quot;a:&quot;, a)
	fmt.Println(&quot;A:&quot;, A)
	fmt.Println(&quot;b:&quot;, b)
	fmt.Println(&quot;B:&quot;, B)
	fmt.Println(b == B)
	fmt.Println(reflect.DeepEqual(b, B))
}

Prints:

a: {a &lt;nil&gt;}
A: {a &lt;nil&gt;}
b: {b 0x10436180}
B: {b 0x10436190}
false
true

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

答案2

得分: 0

你可以使用modify()返回的值。

package main

import (
    "fmt"
)

type Q interface {
    modify() Q           //这里
}

type P struct {
    name    string
    sibling Q
}

func (x P) modify() Q{    //这里
    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() //还有这里

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

有点冗长,但至少可以工作。https://play.golang.org/p/8oM90wriN0

英文:

You can use value returned from modify()

package main

import (
    &quot;fmt&quot;
)

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

type P struct {
    name    string
    sibling Q
}

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

func main() {
    a := P{&quot;a&quot;, nil}
    A := P{&quot;?&quot;, nil}

    b := P{&quot;b&quot;, a}
    B := P{&quot;b&quot;, 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

huangapple
  • 本文由 发表于 2015年4月17日 16:39:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/29694287.html
匿名

发表评论

匿名网友

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

确定