For with a struct (Variable update) - go

Here is an example of a piece of code that I'm trying to use in my program:
package main
import (
"fmt"
"time"
)
type Code struct {
Name string
Alias string
Number int
}
func main() {
test := Code{
Name: "test",
Alias: "test",
Number: 0,
}
codes := []Code{test}
for {
//Other instructions
for _, code := range codes {
code.Number++ // code.Number is incremented but just inside this loop
test.Number++
fmt.Println(code.Number)
fmt.Println(test.Number) // test.Number is incremented
}
fmt.Println(test.Number) // test.Number is incremented
//Other instructions
time.Sleep(5 * time.Second)
}
}
However, every time I come back in my instructions
for _, code := range codes
the value code.Number returns to 0 whereas test.Number is well incremented even outside this loop.
I would like to update the value of my struct in the loop and get this new value at each loop turn.

The instruction codes := []Code{test} makes a copy of test in codes. This copy has the value 0 in Number.
In the for loop, the range instruction makes another copy of the codes[0] struct into code. You increment code.Number, but codes[0].Number is left unmodified. Incrementing test.Number does not affect codes and code.

Related

rand.Intn generating same random sequences multiple time [duplicate]

This question already has answers here:
Go rand.Intn same number/value
(3 answers)
Closed 2 years ago.
I am trying to write a function that generates a random sequence with an alphanumeric character, Unfortunately, the function returns the same random sequence when calling multiple times.
I even tried by seeding the rand with time.Now().UTC().UnixNano(), even though getting the same values again and again
Main Package:
package main
import (
"fmt"
"time"
"userpkg/random"
)
func main() {
fmt.Println(random.RandomHash(32))
fmt.Println(random.RandomHash(32))
fmt.Println(random.RandomHash(32))
fmt.Println(random.RandomHash(32))
}
Random Package
package random
func RandomHash(length int8) string {
rand.Seed(time.Now().UTC().UnixNano())
pool := []byte(`0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ`)
/* allocate a new slice array to store the hash */
buf := make([]byte, length)
for i := int8(0); i < length; i++ {
buf[i] = pool[rand.Intn(len(pool))]
}
rand.Shuffle(len(buf), func(i, j int) {
buf[i], buf[j] = buf[j], buf[i]
})
str := string(buf)
return str
}
Output :
Aau9hmA3YpDezPMIFUtgSUoQfwi7KuWK
Aau9hmA3YpDezPMIFUtgSUoQfwi7KuWK
Aau9hmA3YpDezPMIFUtgSUoQfwi7KuWK
Aau9hmA3YpDezPMIFUtgSUoQfwi7KuWK
Please guide me on how to solve this issue, Thanks
You need to seed the math/rand package once only. If you call the RandomHash() function "very fast", you will seed it to the same value, so it will use the same random values, resulting in the same result! On top of this, on the Go Playground the time is deterministic (it doesn't elapse unless e.g. time.Sleep() is called!).
Move the seeding outside of RandomHash(), e.g. to a package init() function:
func init() {
rand.Seed(time.Now().UnixNano())
}
func RandomHash(length int8) string {
// ...
}
Then each return value of RandomHash() will (likely) be different, e.g. (try it on the Go Playground):
Aau9hmA3YpDezPMIFUtgSUoQfwi7KuWK
8XhJlp6EAXqqbEcPLQL83pw8wUiJRl7D
HGWpHldhGWpzl2KY10ua15T04N1eoPp7
huRNzf4eD7IIuqYNjoMZB5z6r0RFRB64
Also see related question:
How to generate a random string of a fixed length in Go?

How to modify field of a struct in a slice?

I have a JSON file named test.json which contains:
[
{
"name" : "john",
"interests" : ["hockey", "jockey"]
},
{
"name" : "lima",
"interests" : ["eating", "poker"]
}
]
Now I have written a golang script which reads the JSON file to an slice of structs, and then upon a condition check, modifies a struct fields by iterating over the slice.
Here is what I've tried so far:
package main
import (
"log"
"strings"
"io/ioutil"
"encoding/json"
)
type subDB struct {
Name string `json:"name"`
Interests []string `json:"interests"`
}
var dbUpdate []subDB
func getJSON() {
// open the file
filename := "test.json"
val, err := ioutil.ReadFile(filename)
if err != nil {
log.Fatal(err)
}
err = json.Unmarshal(val, &dbUpdate)
}
func (v *subDB) Change(newresponse []string) {
v.Interests = newresponse
}
func updater(name string, newinterest string) {
// iterating over the slice of structs
for _, item := range dbUpdate {
// checking if name supplied matches to the current struct
if strings.Contains(item.Name, name) {
flag := false // declare a flag variable
// item.Interests is a slice, so we iterate over it
for _, intr := range item.Interests {
// check if newinterest is within any one of slice value
if strings.Contains(intr, newinterest) {
flag = true
break // if we find one, we terminate the loop
}
}
// if flag is false, then we change the Interests field
// of the current struct
if !flag {
// Interests holds a slice of strings
item.Change([]string{newinterest}) // passing a slice of string
}
}
}
}
func main() {
getJSON()
updater("lima", "jogging")
log.Printf("%+v\n", dbUpdate)
}
The output I'm getting is:
[{Name:john Interests:[hockey jockey]} {Name:lima Interests:[eating poker]}]
However I should be getting an output like:
[{Name:john Interests:[hockey jockey]} {Name:lima Interests:[jogging]}]
My understanding was that since Change() has a pointer passed, it should directly modify the field. Can anyone point me out what I'm doing wrong?
The problem
Let's cite what the language specification says on the for ... range loops:
A "for" statement with a "range" clause iterates through all entries
of an array, slice, string or map, or values received on a channel.
For each entry it assigns iteration values to corresponding iteration
variables if present and then executes the block.
So, in
for _, item := range dbUpdate { ... }
the whole statement forms a scope in which a variable named item is declared and it gets assigned a value of each element of dbUpdate, in turn, form the first to the last — as the statement performs its iterations.
All assignments in Go, always and everywhere do copy the value of the expression being assigned, into a variable receiving that value.
So, when you have
type subDB struct {
Name string `json:"name"`
Interests []string `json:"interests"`
}
var dbUpdate []subDB
you have a slice whose backing array contains a set of elements, each of which has type subDB.
Consequently, when for ... range iterates over your slice, on each iteration a shallow copy of the fields of a subDB value contained in the current slice element is done: the values of those fields are copied into the variable item.
We could re-write what happes as this:
for i := 0; i < len(dbUpdate); i++ {
var item subDB
item = dbUpdate[i]
...
}
As you can see, if you mutate item in the loop's body, the changes you do to it do not in any way affect the collection's element currently being iterated over.
The solutions
Broadly speaking, the solution is to become fully acquainted with the fact that Go is very simple in most of the stuff it implements, and so range is no magic to: the iteration variable is just a variable, and assignment to it is just an assignment.
As to solving the particular problem, there are multiple ways.
Refer to a collection element by its index
Do
for i := range dbUpdate {
dbUpdate[i].FieldName = value
}
A corollary to this is that sometimes, when the element is complex or you'd like to delegate its mutation to some function, you may take a pointer to it:
for i := range dbUpdate {
p := &dbUpdate[i]
mutateSubDB(p)
}
...
func mutateSubDB(p *subDB) {
p.SomeField = someValue
}
Keep pointers in the slice
If your slice were declated like
var dbUpdates []*subDB
…and you'd keep pointers to (usually heap-allocated) SubDB values,
the
for _, ptr := range dbUpdate { ... }
statement would naturally copy a pointer to a SubDB (anonymous) variable into ptr as the slice contains pointers and so the assignment copies a pointer.
Since all pointers containing the same address are pointing to the same value, mutating the target variable through the pointer kept in the iteration variable would mutate the same thing which is pointed to by the slice's element.
Which approach to select should usually depend on considerations other than thinking about how one would iterate over the elements — simply because once you understand why your code did not work, you do not have this problem anymore.
As usually: if your values are really big, consider keeping pointers to them.
If you values need to be referenced from multiple places at the same time, keep pointers to them. In other cases keep the values directly — this greatly improves CPU data cache locality (simply put, by the time you're about to access the next element its contents will most likely have been already fetched from the memory, which does not occur when the CPU has to chase a pointer to access some arbitrary memory location through it).

How to find empty struct values in Go using reflection?

I have been looking and been struggling with this for a bit. I found this other Stack Overflow question which put me in the right direction but isn't working: Quick way to detect empty values via reflection in Go.
My current code looks like this:
structIterator := reflect.ValueOf(user)
for i := 0; i < structIterator.NumField(); i++ {
field := structIterator.Type().Field(i).Name
val := structIterator.Field(i).Interface()
// Check if the field is zero-valued, meaning it won't be updated
if reflect.DeepEqual(val, reflect.Zero(structIterator.Field(i).Type()).Interface()) {
fmt.Printf("%v is non-zero, adding to update\n", field)
values = append(values, val)
}
}
However I have fmt.Printf which prints out the val and the reflect.Zero I have, and even when they both are the same, it still goes into the if statement and every single field is read as non-zero even though that is clearly not the case. What am I doing wrong? I don't need to update the fields, just add them to the slice values if they aren't zero.
For starters, you are adding val to the values slice if val IS the zero value, not if it isn't. So you should probably check if !reflect.DeepEqual(... instead of what you have. Other than that, your code seems to work fine:
package main
import (
"fmt"
"reflect"
)
type User struct {
Name string
Age int
Email string
}
func main() {
user, values := User{Name: "Bob", Age: 32}, []interface{}(nil)
structIterator := reflect.ValueOf(user)
for i := 0; i < structIterator.NumField(); i++ {
field := structIterator.Type().Field(i).Name
val := structIterator.Field(i).Interface()
// Check if the field is zero-valued, meaning it won't be updated
if !reflect.DeepEqual(val, reflect.Zero(structIterator.Field(i).Type()).Interface()) {
fmt.Printf("%v is non-zero, adding to update\n", field)
values = append(values, val)
}
}
}
outputs the following (Go Playground Link):
Name is non-zero, adding to update
Age is non-zero, adding to update
So it is correctly seeing that the Email field is not initialized (or more correctly, contains the zero value for string).

How to avoid "unused variable in a for loop" error

How to avoid "unused variable in a for loop" error with code like
ticker := time.NewTicker(time.Millisecond * 500)
go func() {
for t := range ticker.C {
fmt.Println("Tick at", t)
}
}()
if I actually don't use the t variable?
You don't need to assign anything, just use for range, like this (on play)
package main
import (
"fmt"
"time"
)
func main() {
ticker := time.NewTicker(time.Millisecond * 500)
go func() {
for range ticker.C {
fmt.Println("Tick")
}
}()
time.Sleep(time.Second * 2)
}
Use a predefined _ variable. It is named "blank identifier" and used as a write-only value when you don't need the actual value of a variable. It's similar to writing a value to /dev/null in Unix.
for _ = range []int{1,2} {
fmt.Println("One more iteration")
}
The blank identifier can be assigned or declared with any value of any type, with the value discarded harmlessly. It's a bit like writing to the Unix /dev/null file: it represents a write-only value to be used as a place-holder where a variable is needed but the actual value is irrelevant.
Update
From Golang docs:
Up until Go 1.3, for-range loop had two forms
for i, v := range x {
...
}
and
for i := range x {
...
}
If one was not interested in the loop values, only the iteration itself, it was still necessary to mention a variable (probably the blank identifier, as in for _ = range x), because the form
for range x {
...
}
was not syntactically permitted.
This situation seemed awkward, so as of Go 1.4 the variable-free form is now legal. The pattern arises rarely but the code can be cleaner when it does.

Go, not getting string value

package main
import (
"fmt"
"io/ioutil"
)
func main() {
// Just count the files...
systems,_ := ioutil.ReadDir("./XML")
fmt.Printf("# of planetary systems\t%d\r\n", len(systems))
// For each datafile
for _,element := range systems {
fmt.Println(element.Name)
}
}
This line...
fmt.Println(element.Name)
Is outputting a memory address instead of what I assume to be the filename string. Why? How do I get the actual string? Thanks.
Also all the addresses are the same, I would expect them to difer, meaning my for-each loop might be broken.
FileInfo.Name is a function of the FileInfo interface; the function's memory address is being printed. To display the name of the file, you need to evaluate the function before printing:
for _, element := range systems {
fmt.Println(element.Name())
}

Resources