4

我对 Go 很陌生,我已经(从常见问题解答中)读到 Go 既是面向对象又不是面向对象的。我想使用 Structs 创建数据结构,并发现自己试图将 Structs 视为简单的对象。我的典型概念证明是建造一辆汽车。我知道汽车是现实世界的对象,因此它适用于 OOP,这在 Go 中可能很奇怪。但我想 User 类会同样方便,所以这对我来说将是一个有用的学习练习和参考。

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

它应该如下所示:

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

或者另一种看待它的方式:

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

Main 向下面的 .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 个气缸。

4

2 回答 2

5

方法

指针与值

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

因此,为了使您的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
于 2013-06-15T22:12:41.607 回答
2

通过 value传递接收者。而是通过指针传递:

func (engine *Engine) Start() {
             ^
}
于 2013-06-15T16:11:40.627 回答