Interfaces as map keys - pointers

In the following code:
package main
import (
"fmt"
)
type Object interface {
String() string
}
type Person struct {
Name string
}
func (p *Person) String() string {
return fmt.Sprintf("person: %s", p.Name)
}
func main() {
dict := map[Object]int{
&Person{Name: "xyz"}: 4,
&Person{Name: "gle"}: 2,
&Person{Name: "kp3"}: 7,
}
fmt.Println(dict[&Person{Name: "xyz"}])
}
It just prints 0, because the map's keys are Objects, which are interfaces. I know why this happens, but is there any way to get around it? I want to be able to have a map whose keys are interface types, but which I can still access fields of.
The only way I've thought of so far would be to iterate through each key and check if the key is equal to the thing I'm searching for, but it would likely be significantly slower.

It does work if you define your method on a struct rather than a pointer: https://play.golang.org/p/zU4sbFe2RB.
If you can't do that in real code, I'm afraid you can't accomplish what you want. These two pointers will be different values, even if they point to similar data.
You can add an Equals(Object) bool method to the Object interface and roll out your own implementation of a map. Alternatively, you can define Hash() string method and use a map[string]whatever.

This seems like it may be a misuse of maps; if you're keying the map off of the String() value of the objects (the only thing the objects have in common), you might try:
package main
import (
"fmt"
)
type Object interface {
String() string
}
type Person struct {
Name string
}
func (p *Person) String() string {
return fmt.Sprintf("person: %s", p.Name)
}
func main() {
xyz := &Person{Name: "xyz"}
gle := &Person{Name: "gle"}
kp3 := &Person{Name: "kp3"}
dict := map[string]int{
xyz.String(): 4,
gle.String(): 2,
kp3.String(): 7,
}
fmt.Println(dict[xyz.String()])
}

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 change value of empty interface that pass as struct reference in golang?

I have many struct that pass as pointer to a function called AutoFilled. each struct is different from another. but some field are the same such as "creator", "createon", "edition"..,
Is there any way to change common field in AutoFilled function?
package main
import (
"fmt"
"time"
)
type User struct {
ID string
Creator string
CreateOn time.Time
Edition int
Name string
Password string
}
type Book struct {
ID string
Creator string
CreateOn time.Time
Edition int
Name string
ISBN string
}
func AutoFilled(v interface{}) {
// Add Creator
// Add CreateOn
// Add Edition (Version) [new is zero, edit increase 1]
}
func main() {
user := User{}
book := Book{}
AutoFilled(&user)
AutoFilled(&book)
fmt.Println(user)
fmt.Println(book)
fmt.Println("Thanks, playground")
}
It looks like you just need a Common struct embedded (sometimes called mixin) in the other structs.
type Common struct {
ID string
Creator string
CreateOn time.Time
Edition int
}
type User struct {
Common
Name string
Password string
}
type Book struct {
Common
Name string
ISBN string
}
Also I would make the AutoFilled function a method on Common. (Using an interface you lose type safety.)
func (c *Common)Autofill() {
// set fields on Common struct
}
func main() {
user := &User{}
user.Autofill()
#AJR has given a very good option. here is an alternative approach.
For each struct (Book and User), create a method called New<StructName. Taking Book as an example
func NewBook() *Book {
return &Book {
//you can fill in default values here for common construct
}
}
You can further extend this pattern by creating a Common struct and pass in that object to NewBook when you are creating it i.e.,
func NewBook(c Common) *Book {
return &Book {
Common: c
//other fields here if needed
}
}
Now in your main code, you will do this
func main() {
c := NewCommon() //this method can create common object with default values or can take in values and create common object with those
book := NewBook(c)
//now you don't need autofill method
fmt.Println("Thanks, playground")
}

Initializing Slice of type Struct in Golang

I have the following structure in Golang
type mystruct struct {
Name string
Power int
}
My purpose is to write a function that takes as input a slice of type *mystuct and returns a slice of type int containing the "Power" property taken from the input slice.
my code is presented below:
package main
import (
"fmt"
)
func main() {
obj := make([]*mystruct, 15)
for i, s := range obj {
s.Power = i
}
fmt.Println(extractpowers(obj))
}
func extractpowers(obj []*mystruct) []int {
powers := make([]int, len(obj))
for i, s := range obj {
powers[i] = s.Power
}
return powers
}
My issue is that the obj := make([]*mystruct, 15) creates a slices of 15 *mystruc pointers initialized to nil; which causes the code within the for loop to raise a panic of type "invalid memory or nil pointer dereference".
My question is what is the proper and fastest way to initialize the slice; (the equivalent of var lst = new List(Of mystruct) in .net)
Regards.
Use a composite literal and take its address in the loop:
for i := range obj {
obj[i] = &mystruct{Power: i}
}
Try it on the Go Playground.

My object is not updated even if I use the pointer to a type to update it

I store some Individual objects in a slice. Before appending it to the slice I print the name of the Individual object.
After I have stored it in the slice, I then retrieve it as a pointer and want to change the name to "Peter", but the change does not work since it still prints "Steve". Why?
type Individual interface {
GetName() *string
SetName(name string)
}
type Person struct {
name string
}
// Implement functions of the Individual interface
func (p Person) GetName() *string {
return &p.name
}
func (p Person) SetName(newName string) {
name := p.GetName();
*name = newName
}
var individuals []Individual
func main() {
person := Person{name: "Steve"}
fmt.Println(person)
individuals = append(individuals, person) // append Person to slice
p1 := individuals[0] // Retrieve the only Person from slice
p1.SetName("Peter") // Change name
fmt.Println(p1) // Should print "Peter", but prints "Steve"
fmt.Println(person) // Should print "Peter", but prints "Steve"
}
Whenever a method wants to modify the receiver, it must be a pointer to the value; the method must have a pointer receiver.
If a method has a non-pointer receiver, a copy will be made and passed when that method is called. From that point, no matter what you do with the receiver, you can only modify the copy, and not the original.
So in your example:
func (p Person) SetName(newName string) {
name := p.GetName();
*name = newName
}
When SetName() is called, a copy is made of the Person. Inside SetName() you obtain the address of the name field of the copy, which you modify. (Actually, a copy of the copy, more on this later...)
Solution: use a pointer receiver:
func (p *Person) SetName(newName string) {
name := p.GetName();
*name = newName
}
From this point on, only *Person implements Individual, so use a pointer when appending:
individuals = append(individuals, &person)
It's tricky, because after this it sill won't work. Why is that?
It is because the Person.GetName() still has a non-pointer receiver:
func (p Person) GetName() *string {
return &p.name
}
So when GetName() is called from SetName(), a copy will be made again, and GetName() will return the address of the name field of the copy, and SetName() will only modify the copy created for calling GetName().
So to make all work, you also have to use pointer receiver for GetName():
func (p *Person) GetName() *string {
return &p.name
}
And now it's working, output (try it on the Go Playground):
{Steve}
&{Peter}
{Peter}
But know that the easiest and recommended way is simply:
func (p *Person) SetName(newName string) {
p.name = newName
}
That's all it takes.
Two things to fix this:
You need the methods attach via a "pointer" method, otherwise the name is only changed inside the method.
You need to use pointers for the actual Person variables, since they need to implement an interface
type Individual interface {
GetName() *string
SetName(name string)
}
type Person struct {
name string
}
// Implement functions of the Individual interface
func (p Person) GetName() *string {
return &p.name
}
func (p *Person) SetName(newName string) {
p.name = newName
}
var individuals []Individual
func main() {
person := &Person{name: "Steve"}
fmt.Println(person)
individuals = append(individuals, person) // append Person to slice
p1 := individuals[0] // Retrieve the only Person from slice
p1.SetName("Peter") // Change name
fmt.Println(p1) // Prints "Steve"
fmt.Println(person) // Prints "Steve"
}
Example on Go Playground.
See https://play.golang.org/p/eg8oYDV6Xx p1 and p2 are already addresses, you don't need to their address (address of address), just print p1 and p2 - they'll be the same as you can see.

How to design structure with modifiable fields?

I am writing a simple game in Go and have some problems with it. My, cut off, code looks like this:
package main
import "fmt"
type Location struct {
X int
Y int
}
type Car struct {
MaxSpeed int
Loc Location
}
func (car Car) SetLocation(loc Location) {
car.Loc = loc
}
func (car Car) GetLocation() Location {
return car.Loc
}
type Bike struct {
GearsNum int
Loc Location
}
func (bike Bike) SetLocation(loc Location) {
bike.Loc = loc
}
func (bike Bike) GetLocation() Location {
return bike.Loc
}
type Movable interface {
GetLocation() Location
SetLocation(Location)
}
type Fleet struct {
vehicles []Movable
}
func (fleet *Fleet) AddVehicles(v ...Movable) {
for _, x := range(v) {
fleet.vehicles = append(fleet.vehicles, x)
}
}
func (fleet *Fleet) WherTheyAre() {
for _, v := range(fleet.vehicles) {
fmt.Println(v.GetLocation())
}
}
func main() {
myCar := Car{MaxSpeed: 200, Loc: Location{12, 34}}
myBike := Bike{GearsNum: 11, Loc: Location{1, 1}}
myFleet := Fleet{}
myFleet.AddVehicles(myCar)
myFleet.AddVehicles(myBike)
myFleet.WherTheyAre()
myCar.SetLocation(Location{0,0})
myFleet.WherTheyAre()
}
The assumption is that Car and Bike are very big structures which I do not want to copy. How should I design the code to be able to modify the location of the car which is the part of the Fleet? Other words how to design the Fleet struct to be able to modify its movable objects?
I have tried to experiment with pointers to interfaces but I was not good idea...
Thanks for help!
The problem is that you've defined the method with value receivers. When you call a method on a receiver the receiving type is actually being passed as an argument, in this case by value and you're modifying that copy.
func (bike Bike) SetLocation(loc Location) {
bike.Loc = loc // modifies local copy of Bike
}
func (bike *Bike) SetLocation(loc Location) {
bike.Loc = loc // modifies the referenced bike
}
You gotta declare your types differently though, or use the & operator in order to call these methods because you have value types in your main. My preference is to use this syntax bike := &Bike{} in almost all cases. I will only go away from it if I have a convenience method for initilization or a very specific reason for using a value type (which is extremely rare).
But basically, you can't make a setter use a value type receiver. If you want to use these structs as value types I would recommend exporting the fields so they can be accessed without getter or setter. Also, just regarding style, I would be displeased to see the use of getters and setters at all unless you actually are abstracting some logic. There's no point in not exporting a field if you're going to provide a setter that directly assigns the value passed in to said field. Also, wasn't looking to closely but you are exporting all fields on your structs so your setters are useless and most programmers would just do bike.Loc = anythingIWantBecauseThisFieldsExportedWhichYouMayThinkOfAsPublic

Resources