我正在阅读一篇ruby教程并尝试使用了解虚拟属性的方式。这是教程中显示的示例。
class Spaceship
def destination
@autopilot.destination
end
def destination=(new_destination)
@autopilot.destination = new_destination
end
end
ship = Spaceship.new
ship.destination = "Earth"
puts ship.destination
根据教程,理想情况下此代码应返回地球,但我遇到以下错误。
class.rb:7:in `destination=': undefined method `destination=' for nil:NilClass (NoMethodError) from class.rb:12:in `<main>'
我很抱歉,但无法确定缺失的部分。
答案 0 :(得分:5)
您需要为@autopilot
变量分配一些内容。
这样的事情应该有效:
class Spaceship
def initialize
@autopilot = Struct.new(:destination).new(nil)
end
def destination
@autopilot.destination
end
def destination=(new_destination)
@autopilot.destination = new_destination
end
end
但是如果你想添加一个虚拟属性,那么将值保存为一个简单的实例变量,如下所示:
class Spaceship
def destination
@destination
end
def destination=(new_destination)
@destination = new_destination
end
end
答案 1 :(得分:1)
正如humza指出的那样,所写的代码将不起作用。
我怀疑作者打算写下面的内容,并希望指出虽然destination
看起来像一个属性(我们可能会将消息destination
发送到一个对象并获取预期的响应),没有相应的实例变量@destination 。我们可能会认为destination
是一个虚拟属性。
class Spaceship
def destination
dosomething
end
def destination=(new_destination)
@autopilot = new_destination
end
def dosomething
@autopilot
end
end
ship = Spaceship.new
ship.destination ="Earth"
puts ship.destination
对象的行为可能就像下一个示例中所示的Spaceship类一样,也就是两个类的接口是相同的(在这种情况下,我们 do 有一个实例变量{{ 1}})。
@destination
发送给Class Spaceship对象的消息不需要知道(也不知道)内部实现。
虚拟属性得到了很好的处理here,并给出了一个更好的示例,其中定义了方法class Spaceship
def destination
@destination
end
def destination=(new_destination)
@destination = new_destination
end
end
ship = Spaceship.new
ship.destination ="Earth"
puts ship.destination
而没有任何相应的实例变量durationInMinutes
。给出的解释非常简洁,我将完整引用它:
这里我们使用属性方法来创建虚拟实例变量。对于外界来说,durationInMinutes似乎是一个像任何其他属性一样的属性。但是,在内部,没有相应的实例变量。
作者继续:
这不仅仅是一种好奇心。在他的具有里程碑意义的“面向对象软件构建”一书中,Bertrand Meyer将其称为统一访问原则。通过隐藏实例变量和计算值之间的差异,您可以屏蔽世界其他地方的类实现。您可以自由地改变未来的工作方式,而不会影响使用您的类的数百万行代码。这是一个很大的胜利。