Ruby 我可以重写赋值运算符的行为吗?

Ruby 我可以重写赋值运算符的行为吗?,ruby,Ruby,我的游戏开发框架有一个点类(存储x,y坐标和其他有用的东西)。我的游戏对象有一个@position属性,它是一个点实例。当@position被修改时,游戏对象将被绘制到其他地方 我的问题是: @someSprite.position = Point.new(100,100) temp = @someSprite.position temp.x = 500 temp成为@someSprite.position的参考。修改它也会更改精灵的位置。这是我不想要的。我希望temp成为一个不同的实例 我不

我的游戏开发框架有一个
类(存储
x
y
坐标和其他有用的东西)。我的游戏对象有一个
@position
属性,它是一个
实例。当
@position
被修改时,游戏对象将被绘制到其他地方

我的问题是:

@someSprite.position = Point.new(100,100)
temp = @someSprite.position
temp.x = 500
temp
成为
@someSprite.position
的参考。修改它也会更改精灵的位置。这是我不想要的。我希望
temp
成为一个不同的实例

我不能这样做:

temp = @someSprite.position.clone
由于框架中的另一个细节:
@someSprite
正在观察它自己的属性,
@someSprite.position

如果使用
clone
,则
temp
也会克隆观察者注册表。当
temp
的状态发生变化时,
@someSprite
将收到通知,造成混乱

我们可以这样做:

temp = @someSprite.position.clone
temp.remove_observer(@someSprite)
但这感觉既不现实又不老练

另一种办法是:

temp = Point.new(@someSprite.position)
其中,我为
创建一个构造函数,它从另一个
获取值(不复制观察者注册表)。这听起来是目前为止最好的方法,但我想要实现的是

temp = @someSprite.position

这能做到吗?在这种情况下,我可以覆盖赋值运算符的行为吗?

您解释了为什么不能使用
clone
,但这并不意味着您不能覆盖
clone
或创建类似
duplicate
的新方法

因此,在您的Point类中,只需定义:

def duplicate
  Point.new(x,y)
end
然后你可以做:

temp = @someSprite.position.duplicate

我假设您正在使用
@position
上的
attr\u reader
来定义精灵的
position
方法。但您也可以定义自己的getter。在这种情况下,我建议您为该职位创建一个明确的getter:

class Sprite
    def position
        return Point.new(@position.x, @position.y)
    end
end

很少有人希望引用对象中精灵的位置,而不是其值的副本;实际上,公开类的私有成员是非常危险的。

Ruby是开源的,因此当然,您可以覆盖赋值运算符,只需对语言
C
略知一二。但我不建议这样做。

赋值运算符在Ruby中永远不可重写。二传手就是二传手;甚至躲在糖后面,让他们看起来使用赋值运算符(他们实际上并不使用赋值运算符,因为setter调用实际上是发送的消息)。@user2246674:建议一个实用的解决方案,而不仅仅是粗鲁无礼如何?@user2246674:你能在回答中进一步阐述你的易变性想法吗?我很好奇,但坦率地说,我仍然没有听到这个建议。@Omega我喜欢最后一种方法(或者重写克隆或添加类似的方法,以便不返回任何附加的观察值之类的额外信息)。记录行为;无法更改赋值的行为。我以前(现在已删除)关于有两种不同类型的评论可能太复杂了。然而,我仍然鼓励为不变性而努力——然而,不变性和可观察性是相对的方法。在我看来,你应该有一个
位置
类,它有一个
和一个观察者。然后就很简单了:
temp=@someSprite.position
只是复制坐标。
temp=@someSprite.position
以上面描述的方式是不可能的吗?正确,因为temp只是一个变量,你要给它赋值,就像你问题的原始注释者所说的那样,没有什么可以覆盖的。例如,如果在另一个对象上设置属性,如
someOtherObject.point=@someSprite.position
,则可以在另一个对象上定义
point=
方法来安全克隆位置。但这并不是你要做的,所以下一个最好的方法是在这个点上放置一个知道如何制作安全拷贝的方法。或者可能是更好的名称,因为
Object
已经支持它们。您是说
Point.new(x,y)
?你用args
x
&
y
调用一个方法
Point
,然后将其结果传递给一个方法
new
。说得好,安德鲁,在回答这个问题之前,我刚刚写了一堆咖啡脚本,脑子里的初始值设定错误。这个主意太棒了。但是如果我这样做,我将无法使用
@someSprite.position.x=100
来修改
@someSprite
的位置,对吗?还是我遗漏了什么?@Omega,是的。你为什么不定义一个
move
(或者任何其他名称)方法:
@someSprite.move(10,20)
?@Omega,在处理游戏开发时,我通常会为精灵创建一个
move
(偏移移动)和
move\u to
(绝对位置)方法。我明白了。嗯,我想这里没有绝对的解决办法,但这两种方法都很好。非常感谢。如果希望能够选择是获取引用还是获取副本,则可以对非引用getter进行不同的命名<代码>位置\u克隆或其他什么。