Go中的OO样式结构对象

时间:2013-06-15 16:04:46

标签: go

我是Go的新手,我读过(来自常见问题解答)Go是OO而不是。我想使用Structs创建数据结构,并发现自己试图将Structs视为简单对象。我的概念证明是建造一辆汽车。我知道汽车是一个真实世界的物体,所以它适合于OOP,这在Go中可能很奇怪。但我认为用户类同样方便,所以这对我来说是一个有用的学习练习和参考。

此示例编译但无法正常运行。它使用多个源文件,因此您必须操作GOPATH并为此创建项目文件夹。

它应该是这样的:

$GOPATH/src/car/car.go
$GOPATH/src/car/parts/engine.go

或另一种看待它的方式:

$ cd /tmp/go/src
$ tree 
.
└── car
    ├── car.go
    └── parts
        └── engine.go

主要请求汽车实例到下面的.Start()。当它回到主要时,汽车没有启动。

/* 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\n", 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
}

分割源文件很方便。所有这些都有效

/* 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
}

运行此输出:

$ 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

在结构上调用函数是有道理的,但我想知道我是否试图以错误的方式操纵内部状态?或许我不明白范围。如果有人可以帮我解决这个问题,我会非常重视它以供参考。

此外,如果某人有首选或惯用的初始化方法。例如,引擎可能默认为4个柱面。

2 个答案:

答案 0 :(得分:5)

  

方法

     

Pointers vs. Values

     

关于接收器的指针与值的规则是值方法   可以在指针和值上调用,但指针方法只能是   在指针上调用。这是因为指针方法可以修改   接收器;在值的副本上调用它们会导致这些   修改被丢弃。

因此,要使Engine Start方法起作用,请使用指针接收器,因为该方法会修改接收器。例如,

package main

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
}

func main() {
    var engine Engine
    fmt.Println(engine.IsStarted())
    engine.Start()
    fmt.Println(engine.IsStarted())
}

输出:

false
Inside the Start() func, started starts off false
Inside the Start() func, then turns to true
true

答案 1 :(得分:2)

你正在通过接收器by value。改为通过指针:

func (engine *Engine) Start() {
             ^
}