新手问题 Ruby 里面如何区分方法和本地变量的

qqren · 2017年05月15日 · 最后由 lithium4010 回复于 2017年05月21日 · 1819 次阅读

color = :red 和 self.color = :orange,为什么第一个是本地变量赋值,而第二个是方法调用?为什么第一个不是隐含的 对 self 调用 color=() 方法呢?

class TrafficLight
  attr_accessor :color

  def progress_color
    case color
    when :orange
      #Don't do this!
      color = :red
    when :green
      #Do this instead!
      self.color = :orange
    else
      raise NotImplementedError, "What should be done if color is already :red? Check with the domain expert, and build a unit test"
    end
  end
end

traffic_light = TrafficLight.new
traffic_light.color = :green
traffic_light.progress_color
traffic_light.color # Now orange
traffic_light.progress_color
traffic_light.color # Still orangea

http://stackoverflow.com/questions/44715/why-do-ruby-setters-need-self-qualification-within-the-class

找到一个合理的说法,就是如果不使用 self.attr= 来显式的调用 attr=() 方法的话,就没办法实现在方法内部定义本地变量的功能了,因为按照 ruby 的方法寻找,最后会到 method_missing。抛出异常。

在 Ruby 里面,local variable 和 setter method 还是挺容易区分的。前者就是一个赋值过程,左值是一个变量。而后者是一个 send message 的过程 + 包装了一层语法糖,self.color = :orange 实际上等同于 self.send('color=', :orange) ,意思是向 self 对象发送一个消息 color= 的信号,参数为 :orange

color = :red 隐含调用方法不就没办法设局部变量了?

Java 写多了?

要是你定义的局部变量和方法名称重名,同样局部变量的优先级也更高。

在类内部调用实例变量时,我一般都是用 @color 这种方式的

变量只有本地。对象加点后面跟的一定是方法。

Ruby 是一门面向对象的语言,对象之间操作全部使用消息传递。

a.x 是向 a 对象发送 :x 消息,这里的 x 自然不是变量而是消息内容了。

同理 a.x= 是发送 :'x=' 消息。

然后如果让 x = 1 也变成向 self 发消息的话,就没法写入本地变量了。

这应该就是‘@’存在的意义吧,正如 6 楼所讲

winse 回复

感觉用 attr_accessor 调用更好写测试

需要 登录 后方可回复, 如果你还没有账号请 注册新账号