为什么Ruby setter方法返回String而不是Symbol作为最后一个表达式计算?

时间:2016-11-04 11:05:45

标签: ruby string casting symbols setter

方法的意外返回值:期望符号

我有以下Ticket类:

class Ticket
  VALID_STATES = %i[open closed invalid wontfix]
  attr_reader :status
  def status= new_state
    new_state = new_state.to_sym
    @status = new_state
  end
end

当传递String而不是Symbol时,即使getter方法返回了正确的值,setter方法也会意外地返回一个String。例如:

t = Ticket.new
t.status = 'closed'
#=> "closed"

t.status
#=> :closed

看起来正确的值是存储作为一个符号,但我不知道为什么当最后一个表达式评估时该方法在REPL返回"closed"的原因应该返回:closed。我的期望是,有问题的表达式应该解析为@status = :closed,因此应该返回一个符号。

有人可以解释为什么我从字符串而不是符号作为setter方法的返回值吗?

警告和自行车脱落预防

  1. 我知道这个例子可以使用@status = new_state.to_sym而不是分配回 new_state ,但是有一些中间代码被删除以创建这个最小的例子。我不想过多地更改代码,因为这样就无法显示我的真实代码在做什么。无论如何,它似乎对这个特定问题没有任何影响;我已经尝试过两种方式。
  2. 我尝试使用Ruby 2.3.1,2.4.0-preview2和JRuby 9.1.4.0,因此它不是特定于版本的。
  3. 在Pry和IRB中,各种调试尝试与REPL特有的其他问题相悖,我将作为一个单独的问题打开。这里的要点是,尝试使用def foo=(str); @foo = str.to_sym; end之类的替代抽象进行调试会进一步导致兔子洞。
  4. 键盘和椅子之间存在问题的可能性极大,但问题的焦点实际上是为什么返回值不是预期的类。

2 个答案:

答案 0 :(得分:5)

预计。来自documentation

  

请注意,对于赋值方法,返回值始终为   忽略。相反,将返回参数:

def a=(value)
  return 1 + value
end

p(a = 5) # prints 5

Ruby允许你链接作业:

foo = bar = 'closed'

上述内容为"closed"foo分配了bar

返回参数并忽略方法的返回值,可以用方法调用替换bar

foo = t.status = 'closed'

如果以上情况将:closed分配给foo,IMO会感到非常惊讶。

如果您真的想要返回值,请使用sendpublic_send

def a=(value)
  return 1 + value
end

p(a = 5)        # prints 5
p(send(:a=, 5)) # prints 6

答案 1 :(得分:1)

答案很简单:在Ruby中,赋值评估为赋值。方法分配没有什么特别之处。