I'm very new to Go and I've read (from the FAQ) that Go is both OO and not. I'd like to create data structures using Structs and find myself trying to think of Structs as simple objects. My canonical proof of concept is building a Car. I understand that a car is a real world object so it lends itself to OOP, which might be weird in Go. But I imagine that a User class would be equally convenient so this will be a useful learning exercise and reference for me.
This example compiles but does not function properly. It uses multiple source files so you'll have to manipulate your GOPATH and create a project folder for this.
It should look like this:
$GOPATH/src/car/car.go
$GOPATH/src/car/parts/engine.go
Or another way to look at it:
$ cd /tmp/go/src
$ tree
.
└── car
├── car.go
└── parts
└── engine.go
Main asks the car instance to .Start() below. When it comes back to main, car is not started.
/* car/car.go */
package main
import (
"car/parts"
"fmt"
)
type Car struct {
sMake string
model string
engine parts.Engine
}
func init() { // optional init of package
// note that we can't use this as a constructor?
}
func main() {
car := Car{
sMake: "AMC",
model: "Gremlin",
}
fmt.Printf("I'm going to work now in my %s %s
", car.sMake, car.model)
fmt.Println("I guess I should start my car.")
car.Start()
fmt.Println("Engine started?", car.engine.IsStarted())
// fail -- engine started is false :(
}
func (car Car) Start() {
fmt.Println("starting engine ...")
car.engine.Start()
fmt.Println("you'd think it would be started here ...", car.engine)
// but it's not
}
Splitting up the source files is convenient. All of this works
/* car/parts/engine.go */
package parts
import (
"fmt"
)
type Engine struct {
cylinders int
started bool
}
func (engine Engine) Start() {
fmt.Println("Inside the Start() func, started starts off", engine.started)
engine.started = true
fmt.Println("Inside the Start() func, then turns to", engine.started)
// this is a sanity check
}
func (engine Engine) IsStarted() bool {
return engine.started
}
Running this outputs:
$ go run car.go
I'm going to work now in my AMC Gremlin I guess I should start my car. starting engine ... Inside the Start() func, started starts off false Inside the Start() func, then turns to true you'd think it would be started here ... {0 true} Engine started? false
Calling functions on the structs makes sense but I wonder if I'm trying to manipulate internal state in the wrong way? Or maybe I don't understand scopes. If someone could help me through this, I'd value it greatly for reference.
Also if someone has a preferred or idiomatic method for initializers. For example, the engine might default to 4 cylinders.