Pointers confusion in Go - pointers

I am having a hard time understanding the below code, I have it working but still don't understand it.
It would really helpful if someone can demystify it
In below code Flags name is not updated to "Changed"
package main
import "fmt"
type Command struct {
Name string
Flags []Flag
}
type Flag struct {
Name string
Shorthand string
}
func getCommand() *Command {
return &Command{Name: "Hello", Flags: []Flag{{"version", "v"}}}
}
func change(cmd *Command) {
for _, flg := range cmd.Flags {
flg.Name = "Changed"
}
}
func main() {
cmd := getCommand()
change(cmd)
fmt.Println(cmd.Flags[0])
}
Correct code. Flags Name is changed to "Changed"
package main
import "fmt"
type Command struct {
Name string
Flags []*Flag
}
type Flag struct {
Name string
Shorthand string
}
func getCommand() *Command {
return &Command{Name: "Hello", Flags: []*Flag{{"version", "v"}}}
}
func change(cmd *Command) {
for _, flg := range cmd.Flags {
flg.Name = "Changed"
}
}
func main() {
cmd := getCommand()
change(cmd)
fmt.Println(cmd.Flags[0])
}
I am sure, my confusion might be trivial, but it has wasted my couple of hours

In your first version, when you do this:
for _, flg := range cmd.Flags {
flg.Name = "Changed"
}
flg is a local variable of type Flag. On each iteration of the for loop, range sets flg to a copy of the next item in cmd.Flags. So when you change that, nothing changes outside that loop.
In your second version, when you do that loop, flg is a local variable of type *Flag, so when range sets it to a copy of the next item in cmd.Flags, flg is pointing to the data you are trying to mutate, and mutating it actually changes that data.

for _, flg := range cmd.Flags {
flg.Name = "Changed"
}
This part is the exact culprit. The first value returned by range is the index(which is ignored here), the second value is a copy of the actual data. When you are using it inside the loop(flg.Name=...), You are assigning the value to Name filed of the copy. You may do this:
for index, _ := range cmd.Flags {
cmd.Flags[index].Name = "Changed"
}
In the second case, you are assigning to Name field of a copy of reference(or memory address) to the Flag, so the value at that memory address get changed.

Related

Pass struct interface to sqlite exec

In Go, I'm trying to pass an interface{} to the statement.Exec() function from go-sqlite3. I'm sure this is a solved problem, but I cannot figure it out.
Basically I have a struct with the row data which I want to pass to a function that will insert it to a sqlite db. The thing is I want to be able to programmatically control what goes into the statement.Exec() function
Here is an excerpt:
type hostRows struct {
domain string
}
type clientRows struct {
name string
}
func main() {
...
data := hostRows{domain: "dom.com"}
insertRow(sqliteDatabase, data)
data2 := clientRows{name: "bob"}
insertRow(sqliteDatabase, data2)
...
}
func insertRow(db *sql.DB, row interface{}) {
insertSQL := "INSERT INTO table(col) VALUES (?)"
statement, _ := db.Prepare(insertSQL)
statement.Exec(row) // here's the issue, how can I extract the element in the interface to pass it to the function for Exec to understand
}
I know that in this example, I could hard code the row type to the struct and type statement.Exec(row.(hostRows).domain), but now the code will break to when the client struct is passed.
here is the deceleration for the Exec function
func (s *Stmt) Exec(args ...interface{}) (Result, error)
I've tried playing with reflect but it hasn't worked for me so far.
My only solution for the moment is using a switch condition that could check and prepare the right command for Exec, but this is less than dodgy.
type hostRows struct {
domain string
}
type clientRows struct {
name string
}
func main() {
...
data := hostRows{domain: "dom.com"}
insertRow(sqliteDatabase, 1, data)
data2 := clientRows{name: "bob"}
insertRow(sqliteDatabase, 2, data2)
...
}
func insertRow(db *sql.DB, i int, row interface{}) {
insertSQL := "INSERT INTO table(col) VALUES (?)"
statement, _ := db.Prepare(insertSQL)
// This basically could be a working solution, but I'm sure there is a better one
switch i {
case 1:
data := row.(hostRows)
statement.Exec(data.domain)
case 2:
data := row.(clientRows)
statement.Exec(data.name)
}
}
edit: corrected the INSERT statement ; forget the columns. corrected statement.Exec(row.domain) to statement.Exec(row.(hostRows).domain)
edit2: added second example
Remember that in order for reflect.Interface() to work, you must export the fields. To achieve what you want using reflection, you could try something like this:
type hostRows struct {
//Should export field to read it using reflect.Value.Interface()
Domain string
}
type clientRows struct {
//Should export field to read it using reflect.Value.Interface()
Name string
}
func insertRow(db *sql.DB, i int, row interface{}) {
rv := reflect.ValueOf(row)
var args []interface{}
for i := 0; i < rv.NumField(); i++ {
args = append(args, rv.Field(i).Interface())
}
db.Exec("Insert Satement...", args...)
}

How to modify the value of a simple type through pointer receiver method in Go?

I wanted to have a custom type based on a basic type and be able to set its value by calling a pointer receiver.
When I run the following program:
package main
import (
"fmt"
"strconv"
)
type FooInt int
func (fi *FooInt) FromString(i string) {
num, _ := strconv.Atoi(i)
tmp := FooInt(num)
fi = &tmp
}
func main() {
var fi *FooInt
fi.FromString("5")
fmt.Printf("%v\n", fi)
}
I receive <nil>. Why doesn't the pointer declared in main() change its value to the address of tmp?
Here is a Go playground link.
All arguments–including the receiver–is a copy inside the function/method. You can only modify the copy.
This applies to pointers too: the receiver value (the fi pointer) is a copy, so you can't modify the original pointer, only the copy.
Usually the receiver is a non-nil pointer, and you modify the pointed value–which results in the original pointed value changed.
In your case you either have to return the pointer and assign the return value:
func (fi *FooInt) FromString(i string) *FooInt {
num, _ := strconv.Atoi(i)
tmp := FooInt(num)
return &tmp
}
func main() {
var fi *FooInt
fi = fi.FromString("5")
fmt.Printf("%v %v\n", fi, *fi)
}
This will output (try it on the Go Playground):
0xc0000b4020 5
Or pass a non-nil pointer to what you want to change, in your case it would be of type **FooInt
func (fi *FooInt) FromString(i string, p **FooInt) {
num, _ := strconv.Atoi(i)
tmp := FooInt(num)
*p = &tmp
}
func main() {
var fi *FooInt
fi.FromString("5", &fi)
fmt.Printf("%v %v\n", fi, *fi)
}
This outputs the same. Try it on the Go Playground.
But easiest would be to just ensure the receiver is not nil, so the pointed value can simply be modified:
func (fi *FooInt) FromString(i string) {
num, _ := strconv.Atoi(i)
*fi = FooInt(num)
}
func main() {
var fi *FooInt
fi = new(FooInt)
fi.FromString("5")
fmt.Printf("%v %v\n", fi, *fi)
}
Output is the same. Try this one on the Go Playground.
The syntax:
func (fi *FooInt) FromString(i string) {
// ...
}
is partly syntactic sugar for:
func FromString(fi *fooInt, i string) {
// ...
}
That is, the fi parameter here is an ordinary local variable. If you assign to it, you replace the pointer value that the caller supplied, rather than writing through the pointer value that the caller supplied. Hence you need to use:
*fi = FooInt(num)
in the body of the function. However, now the caller must pass a non-nil pointer:
var fi FooInt
fi.FromString("5")
for instance.
Here is a complete example, including a method by which you can call the FromString function and pass an explicit pointer.
(I say partly syntactic sugar because this defines FromString as a receiver function or method, which can only be done using this syntax. So the syntax is required—it's not an alternative to some other syntax, as people sometimes mean when using the phrase "syntactic sugar".)

Unable to retain values of golang fields when its returned to the caller of the function

I have a function which accepts slice of values and fields as a set of optional parameters and the function maps each value to a field and returns error if any to the caller as in below
func Unmarshall(source []interface{}, dest ...interface{}) error {
if len(source) != len(dest) {
return errors.New("source and destination doesn't match")
}
for i, s := range source {
dest[i] = s
}
return nil
}
and below the code I have for the caller
for _, r := range rows.Values {
item := entity.Item{}
e :=Unmarshall(r,
&item.Name,
&item.Description,
&item.AddedUTCDatetime,
&item.ModifiedUTCDatetime)
if e == nil {
items = append(items, item)
}
}
But the issue with the above is item.Name,item.Description, &item.AddedUTCDatetime, &item.ModifiedUTCDatetime doesn't retain the values set in the Unmarshall func even though I passed in the pointer to the fields.
Is there anything wrong with the above code?
Is there anything wrong with the above code?
Yes. You're discarding the pointers and are simply overwriting them with new values. To set value that pointer points to, you must dereference it. Could look something like this in your case:
for i, s := range source {
str, ok := dest[i].(*string)
if ok {
*str = s.(string)
}
}
This one takes care of all types
for i, s := range source {
so := reflect.ValueOf(s)
if !reflect.DeepEqual(so, reflect.Zero(reflect.TypeOf(so)).Interface()) {
reflect.ValueOf(dest[i]).Elem().Set(so)
}
}

Why is a pointer to a Go bytes.Buffer required when passing it to another function?

In the code below, write_commas requires the buffer parameter to be a pointer. It works.
The alternative (ie. NOT using a pointer) results in blank output.
Why is it that passing the actual bytes.Buffer fails to print anything? Or put another way, does passing the actual bytes.Buffer create a copy and thus, the bytes get written to a buffer that nothing is reading?
package main
import (
"fmt"
"bytes"
)
func main() {
s := "1234567898"
fmt.Println(Comma(s))
}
func Comma(s string) string {
var buf bytes.Buffer // <-- bytes.Buffer declared here.
sbytes := []byte(s)
decimal := bytes.LastIndex(sbytes,[]byte("."))
if decimal > 0 {
whole_part := sbytes[:decimal]
write_commas(whole_part, &buf) // <-- Address
float_part := sbytes[decimal:len(sbytes)]
for i := len(float_part); i > 0; i-- {
buf.WriteByte(float_part[len(float_part)-i])
}
} else {.
write_commas(sbytes, &buf) // <-- Address
}
return buf.String()
}
func write_commas(byr []byte, buf *bytes.Buffer) { // <-- Why *bytes.Buffer?
for i := len(byr); i > 0; i-- {
buf.WriteByte(byte(byr[len(byr)-i]))
if i > 1 && (i-1) % 3 == 0 {
buf.WriteByte(',')
}
}
}
Any time you pass an argument to a function, it creates a local copy within that function. When you pass a pointer, the function receives a copy of the pointer, which points to the same underlying value. So, if you pass a pointer, the function can affect the value it points to, which the caller will then see. If you pass a copy of the value instead (instead of passing a pointer), the function is manipulating the copy, which has no effect on the caller's own copy.

Creating a map from an array of struct pointers

I have an array of pointers to structs. The structs have a name field. I want to create a map from names to pointers to structs.
Why are all of the values in the registry map identical?
package main
import "fmt"
type Thing struct {
Name string
Value int
}
type Registry map[string]*Thing
func toRegistry(things *[]Thing) Registry {
registry := make(Registry)
for _, thing := range *things {
registry[thing.Name] = &thing
}
return registry
}
func main() {
things := []Thing{{"thingA", 1}, {"thingB", 2}}
registry := toRegistry(&things)
fmt.Println(registry)
}
Sample output: map[thingB:0x10436180 thingA:0x10436180]
GO
EDIT
Per #tvblah's suggestion, things was already a slice, so there's no need to point to it:
package main
import "fmt"
type Thing struct {
Name string
Value int
}
type Registry map[string]*Thing
func toRegistry(things []Thing) Registry {
registry := make(Registry)
for _, thing := range things {
registry[thing.Name] = &thing
}
return registry
}
func main() {
things := []Thing{{"thingA", 1}, {"thingB", 2}}
registry := toRegistry(things)
fmt.Println(registry)
GO
Each map value is a pointer to the single local variable thing.
One fix is to add an pointer to the slice element:
func toRegistry(things []Thing) Registry {
registry := make(Registry)
for i := range things {
registry[things[i].Name] = &things[i]
}
return registry
}
playground
Another option is to store pointers to Thing in the slice:
func toRegistry(things []*Thing) Registry {
registry := make(Registry)
for _, thing := range things {
registry[thing.Name] = thing
}
return registry
}
func main() {
things := []*Thing{&Thing{"thingA", 1}, &Thing{"thingB", 2}}
registry := toRegistry(things)
fmt.Println(registry)
}
playground
I changed the function argument from a pointer to a slice to a slice. This change has no impact on the issue raised on the question, but it's generally how Go code is written. Pointers to slices are rarely used in Go.
You may reassign thing to another local variable on each iteration and store new variable in registry.
package main
import "fmt"
type Thing struct {
Name string
Value int
}
type Registry map[string]*Thing
func toRegistry(things *[]Thing) Registry {
registry := make(Registry)
for _, thing := range *things {
t := thing
registry[thing.Name] = &t
}
return registry
}
func main() {
things := []Thing{{"thingA", 1}, {"thingB", 2}}
registry := toRegistry(&things)
fmt.Println(registry)
}
Playground

Resources