I'm trying to understand the behavior of this small snippet, taken from a larger singly linked-list implementation:
package main
import "fmt"
type Node struct {
Next *Node
Data string
}
func (n *Node) Link(data string) Node {
link := Node{Data: data, Next: n}
return link
}
func main() {
head := Node{Data: "a"}
head = head.Link("b")
fmt.Printf("head = %+v\n", head)
fmt.Printf("head.Next = %+v\n", head.Next)
}
Output:
head = {Next:0xc42000a060 Data:b}
head.Next = &{Next:0xc42000a060 Data:b}
Why is head.Next being linked to itself, and not the "a" node? It has something to do with the re-assignment of the variable name "head", because if you change the line:
head = head.Link("b")
to
head2 := head.Link("b")
and printf head2, everything is correct. Can someone shed light on this unexpected behavior?
You make a node with data "a" and store this node in a variable head which is not a pointer to a Node but a Node. Then you do some weird stuff to change the data of that node and nothing else: The call to link will first get the address of your Node a (to call the pointer method). Then you create a new Node value which has Next point to the Node a. You return that node (and not a pointer to it). Then you overwrite everything in your node head with the new stuff, i.e. Data and Next.
Use pointers througout:
func (n *Node) Link(data string) *Node { return &Node{Data: data, Next: n} }
func main() {
head := &Node{Data: "a"}
fmt.Printf("head = %+v\n", *head)
head = head.Link("b")
fmt.Printf("head = %+v\n", *head)
fmt.Printf("head.Next = %+v\n", *head.Next)
}
Related
package main
import (
"fmt"
)
func main() {
root := map[string]interface{} {
"disney": "world",
}
fmt.Printf("main begin %v\n", root)
addList(root)
fmt.Printf("main after addList %v\n", root)
addMap(root)
fmt.Printf("main after addMap %v\n", root)
}
func addList(root map[string]interface{}) {
root["list"] = make([]interface{},0,3)
mylist := root["list"]
mylist = append(mylist.([]interface{}),"mickeymouse")
fmt.Printf("addList %v\n", mylist)
fmt.Printf("addList %v\n", root)
}
func addMap(root map[string]interface{}) {
root["map"] = make(map[string]interface{})
mymap := root["map"]
mymap.(map[string]interface{})["donald"] = "duck"
fmt.Printf("addMap %v\n", mymap)
fmt.Printf("addMap %v\n", root)
}
I have a root map having the pair "disney"->"world" . To that root map I added a slice having "mickeymouse" in function addList , followed by adding a map with pair "donald"->"duck" in function addMap. However the slice does not get added, whereas the map gets added to the root map. The child map is expected behavior, but the slice addition seems to be an anomaly. I thought the slice was a reference just like a map in golang. What is going on in this case ? It would have worked in Java. Where am I going wrong ? How can I make it work ? In the actual larger problem I dont have the option of returning anything except an error from the functions.
The append function returns a new slice.
Storing values in a map will not produce a new map.
It is therefore only natural that you do not see the new slice, but you do see the map's content updated.
How can I make it work ?
Store the new slice in place of the old, e.g.
mylist := root["list"]
mylist = append(mylist.([]interface{}),"mickeymouse")
root["list"] = mylist
// or, doing it on one line
root["list"] = append(root["list"].([]any), "mickeymouse")
This question already has an answer here:
Can the pointer in a struct pointer method be reassigned to another instance?
(1 answer)
Closed 4 months ago.
I am new to the Golang world & trying to implement a BST in Golang. But while inserting/updating pointers values are not getting updated/inserted. For example in the following code the output is:
3
[]
my code:
package main
import "fmt"
var inOrderTrace []int = []int{}
type node struct {
value int
leftChild *node
rightChild *node
}
type tree struct {
root *node
len int
}
func (myTree tree) inOrderTraverse(node *node) {
if node == nil {
return
}
myTree.inOrderTraverse(node.leftChild)
inOrderTrace = append(inOrderTrace, node.value)
myTree.inOrderTraverse(node.rightChild)
}
func (myTree *tree) insertNode(nodeToManipulate *node, toInsert int) {
if nodeToManipulate == nil {
nodeToManipulate = &node{toInsert, nil, nil}
myTree.len++
return
}
if nodeToManipulate.value > toInsert {
myTree.insertNode(nodeToManipulate.leftChild, toInsert)
} else {
myTree.insertNode(nodeToManipulate.rightChild, toInsert)
}
}
func main() {
myTree := &tree{nil, 0}
var elements []int = []int{1, 0, 2}
for _, element := range elements {
myTree.insertNode(myTree.root, element)
}
myTree.inOrderTraverse(myTree.root)
fmt.Println(myTree.len)
fmt.Println(inOrderTrace)
}
I am expecting the inserted values to be printed.Thanks.
insertNode() has a parameter of pointer type (nodeToManipulate *node). Inside insertNode():
nodeToManipulate = &node{toInsert, nil, nil}
This line will just assign a pointer to the parameter, a local variable. Calling this method from main(), and passing myTree.root, the myTree.root will never be modified, as written above, only the function parameter (which is a copy, a local variable). This means your tree never gets built, the root of tree never gets modified.
To modify something, you have to pass a pointer to it, and modify the pointed value.
For example:
func (myTree *tree) insertNode(pnodeToManipulate **node, toInsert int) {
if *pnodeToManipulate == nil {
*pnodeToManipulate = &node{toInsert, nil, nil}
myTree.len++
return
}
nodeToManipulate := *pnodeToManipulate
if nodeToManipulate.value > toInsert {
myTree.insertNode(&nodeToManipulate.leftChild, toInsert)
} else {
myTree.insertNode(&nodeToManipulate.rightChild, toInsert)
}
}
func main() {
myTree := &tree{nil, 0}
var elements []int = []int{1, 0, 2}
for _, element := range elements {
myTree.insertNode(&myTree.root, element)
}
myTree.inOrderTraverse(myTree.root)
fmt.Println(myTree.len)
fmt.Println(inOrderTrace)
}
With this change output will be (try it on the Go Playground):
3
[0 1 2]
If you don't like double pointers (**), another option is to return the new value and assign it at the caller.
See related / possible duplicates:
Can the pointer in a struct pointer method be reassigned to another instance?
How to modify the value of a simple type through pointer receiver method in Go?
What use case does pointers to pointer (eg **int) have?
tl;dr
I have an arbitrary directed graph defined by a Node struct.
I now want to be able to provide a way to write functions that walk this graph and "tag" each Node with metadata specific to that function.
For example, consider a function to count the number of nodes:
type Node struct {
Nexts []*Node
}
func CountNodes(root *Node) int {
m := make(map[*Node]bool)
return countNodesHelper(root, m)
}
func countNodesHelper(root *Node, m map[*Node]bool) int {
_, seen := m[root]
if seen {
return 0
}
m[root] = true
c := 1
for _, child := range root.Nexts {
c += countNodesHelper(child, m)
}
return c
}
func main() {
n1 := &Node{make([]*Node, 0, 1)}
n2 := &Node{[]*Node{n1}}
n1.Nexts = append(n1.Nexts, n2)
fmt.Println(CountNodes(n1))
}
I could rewrite this if I added a "seen" tag inside the struct:
type NodeWithTag struct {
Nexts []*NodeWithTag
Seen bool
}
func CountNodesWithTag(root *NodeWithTag) int {
if root.Seen {
return 0
}
root.Seen = true
c := 1
for _, child := range root.Nexts {
c += CountNodesWithTag(child)
}
return c
}
func main() {
n1 := &NodeWithTag{make([]*NodeWithTag, 0, 1), false}
n2 := &NodeWithTag{[]*NodeWithTag{n1}, false}
n1.Nexts = append(n1.Nexts, n2)
fmt.Println(CountNodesWithTag(n1))
}
But the Seen tag isn't enough for, say, a DFS on a tree where I also want to find backwards edges (you need to count up to 2 -- never seen, seen, seen a second time along a a single path). So, I want some way to allow the function's implementation to use it's own type to tag the struct with. A rough equivalent of:
type Node struct {
...
// Not valid golang
void* tag
}
but safer that a void* -- The function should be able to statically verify that the tag is the current type that it expects. Is there a way to do this / an alternative approach.
The reason I want to associate the tag with the Node (rather than a separate map / store of the tags) is to allow easy parallelization of the functions that use such tags, farming out the nodes to different goroutines. In the first approach, the map would have to be shared between the goroutines, and this would quickly become a bottleneck because it will require synchronized access.
If you need to support arbitrary data types, you'll need to use an empty interface:
type NodeWithTag struct {
Nexts []*NodeWithTag
Tag interface{}
}
You can assign any value to the Tag field. If you want to verify that the value is a certain type, say MyType, you can use a type assertion:
myVal, ok := node.Tag.(MyType)
If the value is of that type, ok will be true and myVal will contain the typed value.
Go has stumped me again. Hopefully someone can help. I've created a slice (mySlice) that contains pointers to structs (myStruct).
The problem is the "Remove" method. When we're inside "Remove" everything is fine, but once we return, the slice size hasn't changed, and so we see the last element listed twice.
I originally tried writing "Remove" using the same pattern used in the "Add" method, but it wouldn't compile and has been commented out.
I can get it to work by returning the newly created slice to the calling function, but I don't want to do this because mySlice (ms) is a singleton.
And if I hadn't asked enough already...
The code for the "Add" method is working, although I'm not sure how. From what I can gather "Add" is receiving a pointer to the slice header (the 3 item "struct"). From what I've read, the length and capacity of an slice don't get passed to methods (when passing by value), so perhaps passing a pointer to the slice allows the method to see and use the length and capacity thereby allowing us to "append". If this is true, then why doesn't the same pattern work in "Remove"?
Thanks very much for everyone's insights and help!
package main
import (
"fmt"
)
type myStruct struct {
a int
}
type mySlice []*myStruct
func (slc *mySlice) Add(str *myStruct) {
*slc = append(*slc, str)
}
//does not compile with reason: cannot slice slc (type *mySlice)
//func (slc *mySlice) Remove1(item int) {
// *slc = append(*slc[:item], *slc[item+1:]...)
//}
func (slc mySlice) Remove(item int) {
slc = append(slc[:item], slc[item+1:]...)
fmt.Printf("Inside Remove = %s\n", slc)
}
func main() {
ms := make(mySlice, 0)
ms.Add(&myStruct{0})
ms.Add(&myStruct{1})
ms.Add(&myStruct{2})
fmt.Printf("Before Remove: Len=%d, Cap=%d, Data=%s\n", len(ms), cap(ms), ms)
ms.Remove(1) //remove element 1 (which also has a value of 1)
fmt.Printf("After Remove: Len=%d, Cap=%d, Data=%s\n", len(ms), cap(ms), ms)
}
and the results...
Before Remove: Len=3, Cap=4, Data=[%!s(*main.myStruct=&{0}) %!s(*main.myStruct=&{1}) %!s(*main.myStruct=&{2})]
Inside Remove = [%!s(*main.myStruct=&{0}) %!s(*main.myStruct=&{2})]
After Remove: Len=3, Cap=4, Data=[%!s(*main.myStruct=&{0}) %!s(*main.myStruct=&{2}) %!s(*main.myStruct=&{2})]
You were right the first time with Remove1(). Remove gets a copy of the slice and therefore cannot change the length of the slice.
The issue in your remove function is that according to order of operations in Go, slicing comes before dereferencing.
The fix is to change *slc = append(*slc[:item], *slc[item+1:]...) to *slc = append((*slc)[:item], (*slc)[item+1:]...).
However I would recommend the following for readability and maintainability:
func (slc *mySlice) Remove1(item int) {
s := *slc
s = append(s[:item], s[item+1:]...)
*slc = s
}
Because append would not necessarily return the same address of reference to the slice, as Stephen Weinberg has pointed out.
Another way to workaround with this limitation is defining a struct that wraps the slice.
for example:
package main
import "fmt"
type IntList struct {
intlist []int
}
func (il *IntList) Pop() {
if len(il.intlist) == 0 { return }
il.intlist = il.intlist[:len(il.intlist)-1]
}
func (il *IntList) Add(i... int) {
il.intlist = append(il.intlist, i...)
}
func (il *IntList) String() string {
return fmt.Sprintf("%#v",il.intlist)
}
func main() {
intlist := &IntList{[]int{1,2,3}}
fmt.Println(intlist)
intlist.Pop()
fmt.Println(intlist)
intlist.Add([]int{4,5,6}...)
fmt.Println(intlist)
}
output:
[]int{1, 2, 3}
[]int{1, 2}
[]int{1, 2, 4, 5, 6}
I created an Element struct that has a parent and children, created a helper func called SubElement, and a String method that iterates through all children for print:
package main
import "fmt"
type Element struct {
parent *Element
children []Element
tag string
}
func SubElement(parent *Element, tag string) Element {
el := Element{}
el.parent = parent
el.tag = tag
parent.children = append(parent.children, el)
return el
}
func (el Element) String() string {
s := "<" + el.tag + ">"
for _, child := range el.children {
s += child.String()
}
s += "</" + el.tag + ">"
return s
}
func main() {
root := Element{}
root.tag = "root"
a := SubElement(&root, "a")
b := SubElement(&a, "b")
SubElement(&b, "c")
fmt.Println(root) // prints: <root><a></a></root>
fmt.Println(a) // prints: <a><b></b></a>
// and so on
}
The problem I'm experiencing is, only the first tier of children are available from the root node I choose to print. I'm sure it's related to the use of append on parent.children, but lack the understanding of how to resolve this correctly.
To work around the issue, I changed children to map[int]Element. Then in my SubElement func, I "append" with parent.children[len(parent.children)] = el. Then to iterate in the correct order, the String method for-loop is for i:= 0; i < len(el.children); i++, accessing el.children[i].
Still, I'd like to know how to do this correctly with an array. Thanks
An answer to explain why the []Element version didn't work.
Structs are copied as values. In SubElement, you create one Element struct, then when you append it, that actually appends a whole new copy of the struct. When you return el and assign it to a, that makes yet another copy. The address of a is not the address of the Element that was appended.
So, you could get tricky and take the address of the element that's actually in the slice, and that might even look like it's working in a test case, but there's a problem with retaining one these pointers such as you do when you store it back in Element.parent. The problem is that a subsequent append can reallocate the slice, and now your retained pointer points into some orphaned memory rather than the currently valid slice.
If the []*Element version solved some other issues, it's likely that they were issues of storing pointers that were subseqently orphaned.
It is possible to implement a tree with slices of structs, but it takes a clear understanding that retaining pointers into slices is usually a mistake. Since storing the parent pointer is not safe, it's best to just remove it from the struct.
package main
import "fmt"
func main() {
tree := Element{tag: "head"}
tree.SubElement("tier-1")
tree.children[0].SubElement("tier-2")
tree.children[0].SubElement("tier-2")
tree.SubElement("tier-1")
tree.children[1].SubElement("tier-2")
fmt.Println(tree)
}
type Element struct {
children []Element
tag string
}
func (parent *Element) SubElement(tag string) {
parent.children = append(parent.children, Element{tag: tag})
}
func (el Element) String() string {
s := "<" + el.tag + ">"
for _, child := range el.children {
s += child.String()
}
s += "</" + el.tag + ">"
return s
}
This code, at least, works; but if you had other code that was working with pointers, or that used the parent pointer, it would have to be rethought.
The first clue is that SubElement doesn't compile as you have it (edit: had it) there (originally.) You could experiment with making it work, but I recommend you change the Element.children to be []*Element rather than []Element. Here's a working example:
package main
import "fmt"
func main() {
tree := &Element{tag: "head"}
t1 := SubElement(tree, "tier-1")
SubElement(t1, "tier-2")
SubElement(t1, "tier-2")
t1 = SubElement(tree, "tier-1")
SubElement(t1, "tier-2")
fmt.Println(tree)
}
type Element struct {
parent *Element
children []*Element
tag string
}
func SubElement(parent *Element, tag string) *Element {
el := &Element{parent: parent, tag: tag}
parent.children = append(parent.children, el)
return el
}
func (el *Element) String() string {
s := "<" + el.tag + ">"
for _, child := range el.children {
s += child.String()
}
s += "</" + el.tag + ">"
return s
}
Output:
<head><tier-1><tier-2></tier-2><tier-2></tier-2></tier-1><tier-1><tier-2></tier-2></tier-1></head>