Appending to pointer slice - go

Go is my first programming language and I am trying to learn about pointers by writing a program that organizes information based on taxonomies. I'm having some trouble understanding how to append to a pointer slice.
type List struct {
Taxonomies []Taxonomy
}
func (l *List) Add(t Taxonomy) {
var exists bool
var existing *Taxonomy
for _, taxonomy := range l.Taxonomies {
if taxonomy.Name == t.Name {
exists = true
existing = &taxonomy
}
}
if exists {
for _, term := range t.Data {
termExists := false
for _, existingTerm := range existing.Data {
if existingTerm.Name == term.Name {
termExists = true
break
}
}
if termExists {
continue
}
(*existing).Data = append((*existing).Data, term)
}
} else {
l.Taxonomies = append(l.Taxonomies, t)
}
}
type Taxonomy struct {
Name string
Data []Term
}
type Term struct {
Name, Link string
}
I think the problem is toward the bottom, this line:
(*existing).Data = append((*existing).Data, term)
By following the code in a debugger, I can see that the taxonomy stored in the "existing" variable is being updated when the append occurs, but the data is not updated in the actual List.
Can anyone tell me where I am going wrong?

l.Taxonomies is a []Taxonomy, so the taxonomy value is going to be a copy of the element, and changes to that copy will not be reflected in the original List value.
You can iterate using the index to avoid copying the value
for i := range l.Taxonomies {
if l.Taxonomies[i].Name == t.Name {
exists = true
existing = &l.Taxonomies[i]
}
}
However that still leaves the possibility of copying the data passed to methods like Append. Instead it's probably better to use pointers throughout:
type List struct {
Taxonomies []*Taxonomy
}
func (l *List) Add(t *Taxonomy) {
...

Related

type assertion of custom type in go using interface{}

Hi Im new to go and I'm trying implement data structures and algos in go as a learning process. I am trying to interfaces as generics values but I cannot seem to get my custom type of vertex to function properly. I have attached a link to a go playground
type Vertex struct{
Adjacent DoubleLinkedList.DLinkedList
Weight int
Origin int
}
type UGraph struct{
Vertices map[int]DoubleLinkedList.DLinkedList
Weight int
counter int
VerticesList []*Vertex
}
func (UG *UGraph) BFS(node *Vertex, Value interface{})(int) {
visited := make(map[*Vertex]bool) // map that acts as a set
var queue Queue.Queue
queue.Enqueue(node)
for queue.Store.Size > 0 {
V, _ := queue.Dequeue()
nodes := UG.Vertices[((V).(Vertex).Origin).(int64)]
head := nodes.Head
for head.Next != nil {
head = head.Next
if head.Value == Value{
return head.Value.Origin
}
if visited[(head.Value.Origin).(int64)] != true{
visited[head.Value.Origin] = true
queue.Enqueue(head)
}
}
}
return 0
}
https://go.dev/play/p/s3t9LCfBlRI
If I understand correctly your issue, this seems to be your starting point:
You need a Queue with generics support. Then you need to update all structures to handle a T generic type like in the example below.
Be aware that once you have a type T in your struct, your method signature must be updated
You don’t need to use Generics on each type. You may want to use a field with an existing type like Queue[int]
Here we will consider you want all be generic
Enjoy
type DListNode[T any] struct {
Prev *DListNode[T]
Next *DListNode[T]
Value T
}
func (DLL *DLinkedList[T]) AddFront(value T) {
…
}
type Queue[T any] struct {
Store DLinkedList[T] // consider store a pointer
Capacity int
Front T
Rear T
}
func (QQ *Queue[T]) Enqueue(value T) error {
…
}
func (QQ *Queue[T]) Dequeue() (T, error) {
if QQ.isEmpty() {
var zero T
return zero, fmt.Errorf("Queue is currently Empty")
}
…
}
…
// omitting some steps, you can see that you need this in the end:
func (UG *UGraph[T]) BFS(node *Vertex[T], value T) T {

Searching and Returning a node using recursion in minheap binary tree

So I am trying to retrieve a node in a minheap tree by index. The way that it would be called is that I would intiatate a empty MinHeapNode struct and pass by its value via &node so that between recursive function calls, if a match was found it would then return. However it seems that even given a found result the newly assigned empty node would be overwritten by another recursive call that has an empty version of that node. I'm still getting used to the idea of pointers and addresses so I believed that passing the values address would get around this since it would be calling the same value at the same address between calls. But apparently this is something is not correct.
type MinHeapNode struct {
Parent *MinHeapNode
Left *MinHeapNode
Right *MinHeapNode
Value int
Index int
}
func (MHN *MinHeapNode) Insert(value int) {
if !MHN.hasLeftChild() {
MHN.Left = &MinHeapNode{Parent: MHN, Value: value}
return
}
if !MHN.hasRightChild() {
MHN.Right = &MinHeapNode{Parent: MHN, Value: value}
return
}
if MHN.hasLeftChild(){
MHN.Left.Insert(value)
return
}
if MHN.hasRightChild(){
MHN.Right.Insert(value)
return
}
}
func (MHN *MinHeapNode) setIndex(count *int){
index := *count
*count = *count +1
MHN.Index = index
if MHN.hasLeftChild(){
MHN.Left.setIndex(count)
}
if MHN.hasRightChild(){
MHN.Right.setIndex(count)
}
}
func (MHN *MinHeapNode) getIndex(index int, node *MinHeapNode){
if MHN == nil{
return
}
if MHN.Index == index{
node = MHN
return
}
MHN.Left.getIndex(index, node)
MHN.Right.getIndex(index,node)
}
}
type MinHeapTree struct {
Root MinHeapNode
Size int
}
func (MHT *MinHeapTree) getIndex(index int)(*MinHeapNode, error){
if MHT.Size < index +1 {
err := fmt.Errorf("index exceeds tree size")
return nil, err
}
var node MinHeapNode
MHT.Root.getIndex(index, &node)
return &node, nil
}
The issue you are facing appears to be with the statement node = MHN in getIndex (but as your code is incomplete I cannot confirm if this is the only issue).
node = MHN will update the value of node (a parameter, so passed by value and, its scope is the function body). This has no impact on the value of the MinHeapNode that node pointed to at the start of the function. To correct this use *node = *MHN.
This can be demonstrated with a simple program (playground)
type MinHeapNode struct {
Test string
}
func getIndexBad(node *MinHeapNode) {
newNode := MinHeapNode{Test: "Blah"}
node = &newNode
}
func getIndexGood(node *MinHeapNode) {
newNode := MinHeapNode{Test: "Blah"}
*node = newNode
}
func main() {
n := MinHeapNode{}
fmt.Println(n)
getIndexBad(&n)
fmt.Println(n)
getIndexGood(&n)
fmt.Println(n)
}
The output demonstrates that the "bad" function does not update the passed in node:
{}
{}
{Blah}

Using OR logic when checking for multiple keys in map[string]interface{}

I have a map[string]interface{} called mapped:
mapped map[stringinterface{}
I want to iterate through it checking to see if either of these keys exist:
columns
rows
Then if so, I want to append the row or column to a slice of strings called:
columnOrRowArray
I understand that if I just needed to find, for example columns, within mapped I can do this:
var columnOrRowArray []string
if columnsOrRows, ok := mapped["columns"].([]interface{}); ok {
for _, columnOrRow := range columnsOrRows {
if columnOrRowValueIsString, ok = columnOrRow.(string); ok {
columnOrRowArray = append(columnOrRowArray, columnOrRowValueIsString)
}
}
}
What would be a clean way without me duplicating the above for using row logic for the mapped["rows"]?
I want to do something that is basically this:
columnsOrRows, ok := mapped["columns"].([]interface{}) || mapped["rows"].([]interface{}); ok {
So in plain English, "if mapped has a the column or row key, assign to variable columnsOrRows"
Obviously I know the syntax for that is wrong, but I can't find an example of someone doing this
Test for both keys:
columnsOrRows, ok := mapped["columns"].([]interface{})
if !ok {
columnsOrRows, ok = mapped["rows"].([]interface{})
}
if ok {
for _, columnOrRow := range columnsOrRows {
if columnOrRowValueIsString, ok = columnOrRow.(string); ok {
columnOrRowArray = append(columnOrRowArray, columnOrRowValueIsString)
}
}
}
I had to perform a broader check. Check if any of possible keys (more than 2) exist in the map. Ended up writing a utility function to accomplish the task and have the code remain readable.
func StringInSlice(s string, list []string) bool {
for _, item := range list {
if item == s {
return true
}
}
return false
}
func AnyKeyInMap(keys []string, keyMap map[string]interface{}) bool {
for k := range keyMap {
if StringInSlice(k, keys) {
return true
}
}
return false
}
The usage is:
mapped := make(map[string]interface{})
mapped["rows"] = true
if AnyKeyInMap([]string{"rows", "columns"}, mapped) {
fmt.Println("exists")
}
You can play with it here:
https://play.golang.org/p/pz64YidEGMK

Tricky case with value-to-references in for-range

Look to the code - what do you think the output would be? It's return "Third" instead of "Second" and took me a while to understand why.
Do you know a reason?
I get concept of pass-by-value & pass-by-reference quite well but this case is a bit tricky for people coming from languages like Python. So I decided it worth to share.
package main
import "fmt"
type Record struct {
Id int
Name string
}
var records = []Record{
Record{1, "First"},
Record{2, "Second"},
Record{3, "Third"},
}
func findRecod(id int) (foundRecord *Record) {
for _, record := range records {
if record.Id == id {
foundRecord = &record
// You think we can do a break here but imagine we need to do...
}
// ...something more here
}
return foundRecord
}
func main() {
foundRecord := findRecod(2)
if foundRecord == nil {
fmt.Println("Nothing found")
} else {
fmt.Println("Found: ", foundRecord.Name)
}
}
Run it online to check: https://play.golang.org/p/Y_iAl6m7Ms
I've spent some time figuring out what's going on.
You are returning pointer to a record variable which is reused by each iteration of the loop. Last iteration sets the pointer to the third structure.
The reuse of variable has an enormous advantage. It does not allocate memory in every iteration of the loop. This saves a lot of garbage collection time.
This is well know behaviour described in FAQ.
To fix it, return a pointer to an element of the slice. It is safe as slice elements are referencable in Go.
package main
import "fmt"
type Record struct {
Id int
Name string
}
var records = []Record{
Record{1, "First"},
Record{2, "Second"},
Record{3, "Third"},
}
func findRecod(id int) (foundRecord *Record) {
for i, record := range records {
if record.Id == id {
foundRecord = &records[i]
// You think we can do a break here but imagine we need to do...
}
// ...something more here
}
return foundRecord
}
func main() {
foundRecord := findRecod(2)
if foundRecord == nil {
fmt.Println("Nothing found")
} else {
fmt.Println("Found: ", foundRecord.Name)
}
}
Playground

Reference type confusing in Go language

I tried to make Trie data structures by Go Language, but somehow it stuck with References problem,
Here it is. http://play.golang.org/p/ASSGF5Oe9R
// Package main provides ...
package main
import "fmt"
type RootTrie []Trie
type Trie struct {
subtrie []Trie
index byte
}
func (trie *Trie) Insert(data string) *Trie {
if data != "" {
if trie.index == 0 {
trie.index = data[0]
}
if next := trie.containsIndex(data[1:]); next != nil {
//Problem Point
fmt.Println(string(data[1]), "found follwing", string(data[0]))
next.Insert(data[1:])
} else {
nt := &Trie{}
trie.subtrie = append(trie.subtrie, *nt.Insert(data[1:]))
}
}
return trie
}
func (trie *Trie) containsIndex(next string) *Trie {
if next != "" {
for _, st := range trie.subtrie {
if st.index == next[0] {
return &st
}
}
}
return nil
}
func main() {
t := &Trie{}
t = t.Insert("hanyang")
fmt.Println("result:", t)
t = t.Insert("hanyKk")
fmt.Println("result:", t)
t.Insert("hanyK")
}
The following problems happen in second "Insert",
the where I put, //Problem Point
I made containsIndex method for searching next linked trie, and it searched well actually.
But when I updated next property which containsIndex given, its not affected its mother struct trie though.
What I don't understand is I gave it reference type when returning containsIndex, but its still
act liked 'value copied', Why does it not affected its mother structure(trie)?
Thanks!
The problem is in method containsIndex. Golang range by default creates copy each element in slice and assigns copy of this value to st (in your example). Usually to preserve reference to element in slice you should use original slice and its index. In you case method containsIndex should look something like this:
func (trie *Trie) containsIndex(next string) *Trie {
if next != "" {
for i, st := range trie.subtrie {
if st.index == next[0] {
return &trie.subtrie[i]
}
}
}
return nil
}

Resources