Reputation: 2829
I'm creating a simple sorted binary tree that's immutable (well it should behave like its immutable) and I'm unsure how pointer receivers work when they are passed a structure with interfaces.
Here's how I'm defining my binary tree.
type btree interface {
display(io.Writer)
add(int) btree
replace(int, int)//A test to see if we are sharing nodes
}
binary tree nodes are defined like:
type node struct {
data int
left btree
right btree
}
and the empty binary tree node
type empty struct{}
The function and methods
func createEmpty() btree {
return &empty{}
}
Methods for the node struct
//replace is just a test to see if I'm sharing nodes
func (n *node) replace(value, replacement int) {
if n.data < value {
n.left.replace(value, replacement)
} else if n.data > value {
n.right.replace(value, replacement)
} else {
n.data = replacement
}
}
func (n *node) add(data int) btree {
if n.data < data {
l := &node{n.data, n.left.add(data), n.right}
return l
} else if n.data > data {
r := &node{n.data, n.left, n.right.add(data)}
return r
} else {
return n
}
}
func (n *node) display(w io.Writer) {
n.left.display(w)
fmt.Fprintln(w, n.data)
n.right.display(w)
}
Methods for the empty nodes
//replace is just a test to see if I'm sharing nodes
func (*empty) replace(_, _ int) {}
func (e *empty) add(data int) btree {
en := &node{data, e, e}
return en
}
func (*empty) display(w io.Writer) {
fmt.Fprintln(w, "Empty")
}
Please note that the code does work as intended but I'm unsure what happens when I pass a structure with interface members to a pointer receiver. Does the interface data-structure get copied but only a shallow copy so the data it points to remains the same? Is there any documentation on what happens to interfaces in this case?
Here's a working copy of the code below:
package main
import (
"fmt"
"io"
"os"
)
func createEmpty() btree {
return &empty{}
}
type btree interface {
display(io.Writer)
add(int) btree
replace(int, int)
}
type node struct {
data int
left btree
right btree
}
func (n *node) replace(value, replacement int) {
if n.data < value {
n.left.replace(value, replacement)
} else if n.data > value {
n.right.replace(value, replacement)
} else {
n.data = replacement
}
}
func (n *node) add(data int) btree {
if n.data < data {
l := &node{n.data, n.left.add(data), n.right}
return l
} else if n.data > data {
r := &node{n.data, n.left, n.right.add(data)}
return r
} else {
return n
}
}
func (n *node) display(w io.Writer) {
n.left.display(w)
fmt.Fprintln(w, n.data)
n.right.display(w)
}
type empty struct{}
func (*empty) replace(_, _ int) {}
func (e *empty) add(data int) btree {
en := &node{data, e, e}
return en
}
func (*empty) display(w io.Writer) {
fmt.Fprintln(w, "Empty")
}
func main() {
bt := createEmpty().add(5).add(1).add(8).add(2)
bt2 := bt.add(7).add(6).add(10).add(9)
bt.display(os.Stdout)
fmt.Fprintln(os.Stdout, "\n--->")
bt2.display(os.Stdout)
fmt.Fprintln(os.Stdout, "\n\n--->")
//The node with 1 should be shared with bt and bt2
//so if we change bt's node 1 to 4143
//we should see the change in bt2 too
bt.replace(1, 4143)
bt.display(os.Stdout)//We see the change here, 1 is now 4143
fmt.Fprintln(os.Stdout, "\n--->")
bt2.display(os.Stdout)//We see the change here, 1 is now 4143
}
Upvotes: 0
Views: 68
Reputation: 51512
Given this structure:
type node struct {
data int
left btree
right btree
}
and the function f
with q pointer receiver:
func (n *node) f() {}
f
gets a pointer to a node
. Any changes f
makes to the node n
will be reflected on the copy that is used to invoke f
.
To be more precise, when you call n.f()
and if n
is a *node
, then a copy of that pointer is sent to f
, which is still pointing to the same object as n
. If n
is not a pointer, then &n
will be sent to f
.
For your code to work, the left and right btree
interfaces should also containg *node
s, not node
s (you already did this correctly). This is because if you call, for instance, node.left.replace
, you want the value in the node.left
to be replaced. If you had a value-receiver for replace
function, then when you call node.left.replace
a copy of that left node will be sent to the replace
function as a receiver, and the modifications won't be visible on the node.left
node.
Hope this helps.
Upvotes: 1