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

Tod*_*obs 2 ruby string setter symbols casting

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

我有以下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
Run Code Online (Sandbox Code Playgroud)

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

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

t.status
#=> :closed
Run Code Online (Sandbox Code Playgroud)

看起来正确的值被存储为符号,但是我不知道为什么"closed"当最后一个表达式返回时,该方法在REPL处返回: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. 键盘和椅子之间存在问题极有可能,但问题的焦点实际上是为什么返回值不是预期的类.

Ste*_*fan 5

这是预期的.从文档:

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

def a=(value)
  return 1 + value
end

p(a = 5) # prints 5
Run Code Online (Sandbox Code Playgroud)

Ruby允许您链接分配:

foo = bar = 'closed'
Run Code Online (Sandbox Code Playgroud)

以上分配"closed"给和,foobar.

返回参数并忽略方法的返回值允许您bar使用方法调用替换:

foo = t.status = 'closed'
Run Code Online (Sandbox Code Playgroud)

IMO如果将上述内容分配:closed给它将会非常令人惊讶foo.

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

def a=(value)
  return 1 + value
end

p(a = 5)        # prints 5
p(send(:a=, 5)) # prints 6
Run Code Online (Sandbox Code Playgroud)