Go 中的 OO 风格结构对象

我对 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() 。当它回到 main 时,汽车没有启动。


/* 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 缸。


白衣非少年
浏览 178回答 2
2回答

冉冉说

方法指针与值关于接收者的指针与值的规则是值方法可以在指针和值上调用,但指针方法只能在指针上调用。这是因为指针方法可以修改接收者;在值的副本上调用它们将导致这些修改被丢弃。因此,要使您的Engine Start方法工作,请使用指针接收器,因为该方法会修改接收器。例如,package mainimport (    "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())}输出:falseInside the Start() func, started starts off falseInside the Start() func, then turns to truetrue

红糖糍粑

您正在通过value传递接收器。改为通过指针传递:func (engine *Engine) Start() {             ^}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go