以`=`结尾的方法可以接受块吗?

时间:2015-12-27 08:48:38

标签: ruby syntax

当方法名称不以=结尾时,这似乎有效。

class C
  def x= value = nil, &block
  end  
end

c = C.new

c.x = 1                  # => fine
c.x=(2)                  # => fine
c.method(:x=).call { 3 } # => fine
c.x= { 4 }               # => syntax error
c.x= do
  5
end                      # => syntax error

有没有人知道为什么会这样,或者两种语法是否有相似的语法?

样本用法:

logger.level=(:debug) do
  # log at debug level inside this block
end

当然有很多替代方案,例如:

logger.with_level(:debug) do
  # log at debug level inside this block
end

我只是感兴趣,如果我在语法方面缺少某些内容,或者是否有人对此行为有任何解释。

2 个答案:

答案 0 :(得分:3)

=结尾的方法称为Assignment methods,因此适用所有分配规则。

任何赋值语句都可以描述为

LHS = RHS

其中LHS是左手边,RHS是右手边。

RHS被评估为LHS的新值,如果使用尝试 要使用RHS将块指定为{...},它将被解释为Hash文字的定义,并导致编译错误为无效散列。同样,do...end块将导致其他编译错误。

赋值方法应始终具有单个参数,其值可以分配给实例变量,或者其值可用于为实例变量派生新值。

如果您希望可以使用Proclambda作为参数,因为它们是对象。

class C
  def x= value
    @x = (value.class == Proc ? value.call : value)
    p @x
  end  
end

c = C.new

# fine
c.x = -> {10}
c.x = lambda {20}
c.x = Proc.new {30}

答案 1 :(得分:3)

他们可以,但以常规方式调用它们会导致块被评估为哈希,从而为您提供SyntaxError。您仍然可以使用Object#public_send / Object#send

来呼叫他们
def foo=
  puts 'bar'
  yield
  puts 'baz'
end

public_send(:foo=) { puts 'quiz' } # bar quiz baz
foo= { puts 'fail' } # SyntaxError