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?
Related
I'm new in Golang.
I executed the code below. I get empty humans array in the end.
What should I do in func F?
For testing(monkeypatch) sake. I have to follow the way how the origin func is called.
package main
import (
"fmt"
)
type Human struct {
Name string
}
type Cat struct {
Name string
}
func F(arr interface{}) {
switch arr.(type) {
case *[]*Human:
arr = &[]*Human{{Name: "abc"}}
arr = arr.(*[]*Human)
case *[]*Cat:
arr = &[]*Cat{{Name: "meow"}}
arr = arr.(*[]*Cat)
}
}
func main() {
var humans []*Human
F(&humans)
fmt.Println(humans)
var cats []*Cat
F(&cats)
fmt.Println(cats)
}
The answer, and the main issue cause as well, is that Go always uses pass by value (or copy of the value) when arguments are passed around to function or assigned to variables.
Your function F takes an arr argument:
func F(arr interface{}) {
//...
}
When called from your main function, you are passing an []*Human pointer as an argument, which values will be copied and fed to your function F for execution.
Going back to your function F body, the arr will be having the same value passed by main, which happens to be the address to the original []*Human struct. Upon assigning a new value to arr:
func F(arr interface{}) {
switch arr.(type) {
case *[]*Human:
arr = &[]*Human{{Name: "abc"}}
// ...
}
}
You are assigning a new value to the local arr variable and not to the original pointer, which remains, indeed, unchanged.
To update the value toward which the argument pointer is referring to, you should used the dereferrence symbol:
func F(arr interface{}) {
switch arr := arr.(type) {
case *[]*Human:
*arr = []*Human{&Human{Name: "abc"}}
fmt.Println(arr)
// ...
}
}
Note the switch arr := arr.(type) statement which creates a new arr variable (shadowing the argument arr) with the interface dynamic type to be able to assign the proper value to it.
I have a function with following definition:
type TreeNode struct {
Val int
Left *TreeNode
Right *TreeNode
}
func BuildTree(input []interface{}) *TreeNode {
// ...
newNode := new(TreeNode)
newNode.Val = input[0] // here caused the error
// ...
}
I tried to do the type assertion:
if _, ok := input[0].(int); ok {
tree.Val = input[0]
}
but still give me the same error
input is a slice like [1,2,3,4] or [1, nil, 2, 3, nil, 4], nil means that it is an empty node, I don't use input[]int because maybe there are some nodes' value is 0
A type assertion does not impact the object you are asserting on. Instead, it returns the value stored in the interface alongside a success bool.
This means that you need to save this returned value and use it. In your case, change your type assertion to the following:
if res, ok := input[0].(int); ok {
tree.Val = res
}
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)
}
I want to know is there a generic way to write code to judge whether a slice contains an element, I find it will frequently useful since there is a lot of logic to fist judge whether specific elem is already in a slice and then decide what to do next. But there seemed not a built-in method for that(For God's sake, why?)
I try to use interface{} to do that like:
func sliceContains(slice []interface{}, elem interface{}) bool {
for _, item := range slice {
if item == elem {
return true
}
}
return false
}
I thought interface{} is sort of like Object of Java, but apparently, I was wrong. Should I write this every time meet with a new struct of slice? Isn't there a generic way to do this?
You can do it with reflect, but it will be MUCH SLOWER than a non-generic equivalent function:
func Contains(slice, elem interface{}) bool {
sv := reflect.ValueOf(slice)
// Check that slice is actually a slice/array.
// you might want to return an error here
if sv.Kind() != reflect.Slice && sv.Kind() != reflect.Array {
return false
}
// iterate the slice
for i := 0; i < sv.Len(); i++ {
// compare elem to the current slice element
if elem == sv.Index(i).Interface() {
return true
}
}
// nothing found
return false
}
func main(){
si := []int {3, 4, 5, 10, 11}
ss := []string {"hello", "world", "foo", "bar"}
fmt.Println(Contains(si, 3))
fmt.Println(Contains(si, 100))
fmt.Println(Contains(ss, "hello"))
fmt.Println(Contains(ss, "baz"))
}
How much slower? about x50-x60 slower:
Benchmarking against a non generic function of the form:
func ContainsNonGeneic(slice []int, elem int) bool {
for _, i := range slice {
if i == elem {
return true
}
}
return false
}
I'm getting:
Generic: N=100000, running time: 73.023214ms 730.23214 ns/op
Non Generic: N=100000, running time: 1.315262ms 13.15262 ns/op
You can make it using the reflect package like that:
func In(s, e interface{}) bool {
slice, elem := reflect.ValueOf(s), reflect.ValueOf(e)
for i := 0; i < slice.Len(); i++ {
if reflect.DeepEqual(slice.Index(i).Interface(), elem.Interface()) {
return true
}
}
return false
}
Playground examples: http://play.golang.org/p/TQrmwIk6B4
Alternatively, you can:
define an interface and make your slices implement it
use maps instead of slices
just write a simple for loop
What way to choose depends on the problem you are solving.
I'm not sure what your specific context is, but you'll probably want to use a map to check if something already exists.
package main
import "fmt"
type PublicClassObjectBuilderFactoryStructure struct {
Tee string
Hee string
}
func main() {
// Empty structs occupy zero bytes.
mymap := map[interface{}]struct{}{}
one := PublicClassObjectBuilderFactoryStructure{Tee: "hi", Hee: "hey"}
two := PublicClassObjectBuilderFactoryStructure{Tee: "hola", Hee: "oye"}
three := PublicClassObjectBuilderFactoryStructure{Tee: "hi", Hee: "again"}
mymap[one] = struct{}{}
mymap[two] = struct{}{}
// The underscore is ignoring the value, which is an empty struct.
if _, exists := mymap[one]; exists {
fmt.Println("one exists")
}
if _, exists := mymap[two]; exists {
fmt.Println("two exists")
}
if _, exists := mymap[three]; exists {
fmt.Println("three exists")
}
}
Another advantage of using maps instead of a slice is that there is a built-in delete function for maps. https://play.golang.org/p/dmSyyryyS8
If you want a rather different solution, you might try the code-generator approach offered by tools such as Gen. Gen writes source code for each concrete class you want to hold in a slice, so it supports type-safe slices that let you search for the first match of an element.
(Gen also offers a few other kinds of collection and allows you to write your own.)
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}