我正在用 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 结构以能够修改其可移动对象? 我曾尝试使用指向接口(interface)的指针进行试验,但我不是个好主意...
感谢您的帮助!
最佳答案
问题是您已经定义了带有值接收者的方法。当您在接收器上调用方法时,接收类型实际上是作为参数传递的,在这种情况下是按值传递的,并且您正在修改该副本。
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 的使用。如果您要提供一个直接将传入的值分配给所述字段的 setter ,那么不导出字段是没有意义的。此外,并没有仔细查看,但您正在导出结构上的所有字段,因此您的 setter 是无用的,大多数程序员只会做 bike.Loc = anythingIWantBecauseThisFieldsExportedWhichYouMayThinkOfAsPublic
关于pointers - 如何设计具有可修改字段的结构?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30792131/