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
Related
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")
}
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()])
}
For example
var myStructRef *Vertex
var myStruct Vertex
myStructRef = &Vertex{2, 3}
myStruct = Vertex{2, 3}
fmt.Println(myStructRef)
fmt.Println(myStruct)
changeByReferenceStruct(myStructRef)
changeByValueStruct(myStruct)
fmt.Println(myStructRef)
fmt.Println(myStruct)
And
func changeByValueStruct(myStruct Vertex) {
myStruct.X = 5
fmt.Println(myStruct)
}
func changeByReferenceStruct(myStruct *Vertex) {
myStruct.X = 7
fmt.Println(myStruct)
}
Isn't both myStructRef *Vertex and myStruct Vertex a pointer pointing to the struct itself? Why is there a discrepancy in behavior when I modify the struct in a function?
Is golang creating a new struct in changeByValueStruct when it resolves the parameter?
When you pass a pointer as an argument, what happens under the hood is that a copy of that pointer is created and passed to the underlying function. It should not be confused with pass-by-reference.
Let's look at an example to better grasp it:
package main
import (
"fmt"
)
type Point struct {
x int
y int
}
func (p Point) String() string {
return fmt.Sprintf("(%d, %d)", p.x, p.y)
}
func modifyValue(point Point) {
point.x += 10
}
func modifyPointer(point *Point) {
point.x = 5
point.y = 5
}
func modifyReference(point *Point) {
point = &Point{5, 5}
}
func main() {
p := Point{0, 0}
fmt.Println(p) // prints (0, 0)
modifyValue(p)
fmt.Println(p) // prints (0, 0)
modifyPointer(&p)
fmt.Println(p) // prints (5, 5)
p = Point{0, 0}
modifyReference(&p)
fmt.Println(p) // prints (0, 0)
}
What happens inside the modifyValue function is that a totally different instance of a Point structure is modified, so the value passed when calling the function is unaffected.
In the second example, a pointer to the structure is passed so the fields of the structure can be modified in a way that is visible from outside.
The most interesting point is made by the last function, modifyReference. If you are familiar with the pass by reference paradigm available in other languages you would expect to be able to modify the referenced object altogether, but this doesn't happen. It's because you're modifying a copy of the pointer passed as argument.
You may wonder, if everything is passed by value, when should you pass pointers and when values. Passing values assures the caller function that the passed structure cannot suffer any changes, so when you need this behaviour, go for the value. The downside of this is that a copy of the entire object is made and, if it is too big, memory becomes a concern.
If you're passing a big structure as an argument, using a pointer is better because it saves space, but you lose the guarantee that the object won't suffer any changes.
Passing struct to function argument makes copy of values. And passing pointer of struct doesn't. So passing struct can't update field value.
package main
import (
"fmt"
)
type Foo struct {
value int
}
func PassStruct(foo Foo) {
foo.value = 1
}
func PassStructPointer(foo *Foo) {
foo.value = 1
}
func main() {
var foo Foo
fmt.Printf("before PassStruct: %v\n", foo.value)
PassStruct(foo)
fmt.Printf("after PassStruct: %v\n", foo.value)
fmt.Printf("before PassStructPointer: %v\n", foo.value)
PassStructPointer(&foo)
fmt.Printf("after PassStructPointer: %v\n", foo.value)
}
https://play.golang.org/p/AM__JwyaJa
The following program runs fine.
package main
import (
"fmt"
)
type Person interface {
Hello()
}
type Joker struct {
Name string
}
func (j Joker) Hello() {
fmt.Println(j.Name, "says, \"Hello!\"")
}
func main() {
var j Joker = Joker{"Peter"}
invokeHello(j)
}
func invokeHello(p Person) {
p.Hello()
}
Here is the output.
$ go run foo.go
Peter says, "Hello!"
But when I change the Hello method to receive a pointer, I get errors.
package main
import (
"fmt"
)
type Person interface {
Hello()
}
type Joker struct {
Name string
}
func (j *Joker) Hello() {
fmt.Println(j.Name, "says, \"Hello!\"")
}
func main() {
var j *Joker = &Joker{"Peter"}
invokeHello(j)
}
func invokeHello(p *Person) {
p.Hello()
}
Here are the errors.
$ go run bar.go
# command-line-arguments
./bar.go:21: cannot use j (type *Joker) as type *Person in argument to invokeHello:
*Person is pointer to interface, not interface
./bar.go:25: p.Hello undefined (type *Person has no field or method Hello)
How can I fix the second program?
func invokeHello(p *Person) {
p.Hello()
}
p is type *Person, *Joker implement interface Person, revert invokeHello to:
func invokeHello(p Person) {
p.Hello()
}
this will fix the second program.
I think you have misleading about golang interface type
An interface type specifies a method set called its interface. A variable of interface type can store a value of any type with a method set that is any superset of the interface. Such a type is said to implement the interface.
Fix
You can't use pointers to interface type.
That is the problem:
func invokeHello(p *Person) {
p.Hello()
}
Should be:
func invokeHello(p Person) {
p.Hello()
}
Interface implementation
Types implement interfaces. If type has methods appropriate to a methods declared in an interface than the interface is implemented by the type.
Interfaces in Go provide a way to specify the behavior of an object: if something can do this, then it can be used here.
Types vs pointers to a types
Type and *Type are different types. For example *Type could implement an interface but Type can not implement it. But *InterfaceType really has no sence to use.
If you want to receive pointer to a type in a function which expects an interface type, implement the interface with pointer receiver, like you did in a second example.
Example:
type Person interface {
Hello()
}
type Joker struct {
Name string
}
/*
A Hello method declared with a pointer receiver which means that a pointer to
the Joker type (*Joker) not Joker type itself implements Person interface.
*/
func (j *Joker) Hello() {
fmt.Println(j.Name, "says, \"Hello!\"")
}
/*
invokeHello receives ANY type which statisfies Person interface.
In this case this is pointer to Joker type.
*/
func invokeHello(p Person) {
p.Hello()
}
func main() {
i := Joker{"Peter"}
j := &i
// Note difference between types
fmt.Printf(
"Joker type: %s\nPointer to Joker type: %s\n",
reflect.TypeOf(i), reflect.TypeOf(j))
invokeHello(j)
}
Otherwise if you want to receive a value of a type, implement the interface with value receiver, like you did in a first example.
Suppose, I am writing a minesweeper game, and i have a struct to hold the game field, that contains a 2D array with mines. Suppose, i want to initialize it with some mines. Is there a way to say gameField GameField = new(GameField, 30), similar to what i'd do in java?
Here is some code to illustrate my point:
type GameField struct {
field [20][20] int
}
func (this *GameField) scatterMines(numberOfMines int) {
//some logic to place the numberOfMines mines randomly
}
What i want is to call an initializer and have that scatterMines func executed automatically.
A pattern I've seen in Go structs is a corresponding NewXxx method (e.g., image pkg):
type GameField struct {
field [20][20] int
}
func NewGameField(numberOfMines int) *GameField {
g := new(GameField)
//some logic to place the numberOfMines mines randomly
//...
return g
}
func main() {
g := NewGameField(30)
//...
}
Go objects have no constructors, so there is no way to have scatterMines function executed automatically at variable initialization. You need to call the method explicitly:
var GameField g
g.scatterMines(30)
See also http://golang.org/ref/spec#The_zero_value.