Ruby中的虚拟属性

Ruby中的虚拟属性,ruby,attributes,virtual,Ruby,Attributes,Virtual,我正在学习ruby教程,并试图使用它来理解虚拟属性是如何工作的。这是本教程中显示的示例 class Spaceship def destination @autopilot.destination end def destination=(new_destination) @autopilot.destination = new_destination end end ship = Spaceship.new ship.destination = "Earth

我正在学习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>'
class.rb:7:in`destination=':未定义类中nil:NilClass(NoMethodError)的方法`destination='

很抱歉,我无法识别丢失的部分。

您需要为
@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
如前所述,编写的代码将无法工作

我怀疑作者的意图是编写如下内容,并想指出,尽管
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类,如下一个示例所示,即两个类的接口是相同的(在本例中,我们有一个实例变量
@destination

发送给Spaceship类对象的消息不需要知道(也不知道)内部实现

虚拟属性得到了很好的处理,并给出了一个更好的示例,其中定义了一个方法
durationminutes
,而没有任何相应的实例变量
@durationminutes
。给出的解释非常简洁,我将完整引用:

在这里,我们使用属性方法创建了一个虚拟实例变量。在外界看来,持续时间分钟似乎是一个属性,就像其他属性一样。但在内部,没有相应的实例变量

作者继续:

这不仅仅是一种好奇。Bertrand Meyer在其具有里程碑意义的著作《面向对象的软件构建》中称之为统一访问原则。通过隐藏实例变量和计算值之间的差异,您可以保护世界其他地方不受类实现的影响。您可以自由地更改将来的工作方式,而不会影响使用类的数百万行代码。这是一个巨大的胜利


什么是自动驾驶仪?它没有被初始化。你在哪里初始化
@autopilot
?你能解释一下这一行的作用吗
@autopilot=Struct.new(:destination)。new(nil)
它创建了一个新的
结构
,带有
destination
属性,该属性具有
nil
值。在控制台中运行它以签出输出。在同一个对象上,可以使用
destination
destination=
方法。但为什么我们需要一个新类来为@autopilot变量赋值呢。请原谅我对这个话题的无知。我对Ruby是新手。提前谢谢。我们不需要这样做。我只是想让你现有的代码正常工作。第二个版本是你真正想要的。我必须注册才能看到整个教程。我不想那样做。但是虚拟属性映像中的代码根本不正确-它与您共享的代码相同。
class Spaceship
  def destination
    @destination
  end

  def destination=(new_destination)
    @destination = new_destination
  end
end

ship = Spaceship.new
ship.destination ="Earth"
puts ship.destination