在初始化之外声明实例变量

时间:2017-05-22 01:32:10

标签: ruby class

我试图将摄氏温度转换为华氏温度,反之亦然。如下所示,实例变量@temperature分别在方法celsius=fahrenheit=中定义。

class Temperature
  def self.ctof(temp)
    (temp * 9 / 5.0) + 32
  end

  def self.ftoc(temp)
    (temp - 32) * (5 / 9.0)
  end

  def initialize(options)
    if options[:f]
      self.fahrenheit = options[:f]
    else
      self.celsius = options[:c]
    end
  end

  def fahrenheit=(temp)
    @temperature = self.class.ftoc(temp)
  end

  def celsius=(temp)
    @temperature = temp
  end

  def in_fahrenheit
    self.class.ctof(@temperature)
  end

  def in_celsius
    @temperature
  end
end

这让我感到困惑,因为我从未见过在initialize方法之外定义的实例变量。我希望有人能帮我理解这里发生的事情。

2 个答案:

答案 0 :(得分:1)

当您致电Temperature.new(c: 0)时,这将设置celsius=访问者,它将实例变量@temperature(意味着始终以摄氏度为单位)设置为0

当您致电Temperature.new(f: 32)时,会设置fahrenheit=访问者,将实例变量@temperature设置为Temperature.ftoc(32)0.0

调用in_celsius只会在示例中返回@temperature0

致电in_fahrenheit会返回Temperature.ctof(0)32.0

在构造函数外部定义的实例变量没有什么神奇之处。关键是它是一个在整个实例方法中可用的变量。

答案 1 :(得分:0)

将实例变量设置在initialize之外是完全正确的。这正是二传手做的事情。您可能已经知道attr_accessor - 在调用attr_accessor :foo时,它会为实例变量foo创建一个getter foo=和一个setter @foo,即两个等效的方法:

def foo
  @foo
end

def foo=(value)
  @foo = value
end

在您的代码中,in_celsiuscelsius=就是这样:@temperature的getter和setter。

但是你的代码确实看起来有点复杂。我认为这是因为Temperature必须处理华氏度和摄氏度。您可以通过为每个温度范围提供单独的类来简化它:

class Celsius
  attr_reader :value

  def initialize(value)
    @value = value
  end

  def to_celsius
    self
  end

  def to_fahrenheit
    Fahrenheit.new((value * 9 / 5.0) + 32)
  end
end

class Fahrenheit
  attr_reader :value

  def initialize(value)
    @value = value
  end

  def to_celsius
    Celsius.new((value - 32) * (5 / 9.0))
  end

  def to_fahrenheit
    self
  end
end

现在每个类都有一个实例变量@value,它在initialize内设置。

temperature = Celsius.new(0)
#=> #<Celsius:0x007fb83d8b33a8 @value=0>

temperature.to_fahrenheit
#=> #<Fahrenheit:0x007fb83d8b3128 @value=32.0>