【问题标题】:How to design structure with modifiable fields?如何设计具有可修改字段的结构?
【发布时间】:2015-06-11 21:56:01
【问题描述】:

我正在用 Go 编写一个简单的游戏,但遇到了一些问题。我的,切断,代码如下所示:

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()
}

假设 Car 和 Bike 是我不想复制的非常大的结构。我应该如何设计代码才能修改作为车队一部分的汽车的位置?换句话说,如何设计 Fleet 结构以能够修改其可移动对象? 我曾尝试尝试使用指向接口的指针,但我不是个好主意...

感谢您的帮助!

【问题讨论】:

  • CarBike 上的方法需要指针接收器,而不是值接收器。
  • 这不是重点。我在问如何拥有一个“处理程序”,通过它我将能够修改 Fleet 中的车辆。 Func: AddVehicles 将复制它,我无法将其参数类型更改为指针,因为类型是接口。
  • 只需将指针传递给AddVehicles: myFleet.AddVehicles(&myCar); myFleet.AddVehicles(&myBike);您不必(也不应该)将vehicles []Movable 更改为vehicles []*Movable
  • 它有效...谢谢。但我的心只是炸了。如果类型不正确,它如何工作?

标签: pointers go interface


【解决方案1】:

问题是您已经定义了带有值接收器的方法。当您在接收器上调用方法时,接收类型实际上是作为参数传递的,在这种情况下是按值传递,并且您正在修改该副本。

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
    }

你必须以不同的方式声明你的类型,或者使用& 操作符来调用这些方法,因为你的main中有值类型。我的偏好是在几乎所有情况下都使用这种语法bike := &Bike{}。如果我有一种方便的初始化方法或使用值类型的非常具体的原因(这非常罕见),我只会离开它。

但基本上,您不能让 setter 使用值类型接收器。如果您想将这些结构用作值类型,我建议您导出字段,以便无需 getter 或 setter 即可访问它们。另外,就风格而言,除非您实际上是在抽象一些逻辑,否则我会完全不高兴看到 getter 和 setter 的使用。如果您要提供一个直接将传入的值分配给所述字段的设置器,那么不导出字段是没有意义的。另外,没有仔细观察,但是您正在导出结构上的所有字段,因此您的设置器无用,大多数程序员只会做bike.Loc = anythingIWantBecauseThisFieldsExportedWhichYouMayThinkOfAsPublic

【讨论】:

  • 请看上面的评论。关于吸气剂和二传手我同意。它们没有意义我只是想拥有界面。也许我应该想办法更方便。
  • @mmburr 我明白了。我想我将保持原样,尽管您要使用的解决方案更多的是重构/重新设计,而不是您无法修改这些字段的原因。如果您实际上没有使用 Tim 在 cmets 中提出的建议,请说出来,我会帮助您找到可行的解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-12-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多