是否可以将块声明为默认值?

时间:2013-12-01 16:35:52

标签: ruby lambda block

我想编写一个接受块的方法,如果没有给定块,则应使用默认块。所以我希望有这样的东西:

def say_hello(name, &block = ->(name) { puts "Hi, #{name}" })
  # do something
end 

但是当我尝试这样做时,我收到了语法错误。

我知道我可以使用block_given?处理我的问题。但我对第一种方法感兴趣。 我错过了什么或者这是不可能的吗?

4 个答案:

答案 0 :(得分:2)

您不能在方法定义中声明默认块,但是如果没有给出自定义块,您可以使用一个小技巧。

def say_hello(name)
  block = block_given? ? Proc.new : ->(name) { puts "Hi, #{name}" }
  block.call(name)
end

# This example uses a custom block
say_hello('weppos') { |name| puts "Hello, #{name}!" }
# => Hello, weppos!

# This example fallbacks to the default
say_hello('weppos')
# => Hi, weppos!

让我解释一下。让我们从一个更易阅读的版本开始。

def say_hello(name, &block)
  block = block ? block : ->(name) { puts "Hi, #{name}" }
  block.call(name)
end

您定义接受块的方法,然后检查是否定义了块。如果没有,则指定自定义块。最后,执行块。

让我们稍微提升一下。你可以使用block_given吗?检查块是否通过

def say_hello(name, &block)
  block = block_given? ? block : ->(name) { puts "Hi, #{name}" }
  block.call(name)
end

这也允许您跳过方法定义中块(&block)的声明。

def say_hello(name)
  if block_given?
    yield name
  else
    # This is rendundant, but it's for clarity
    block = ->(name) { puts "Hi, #{name}" }
    block.call(name)
  end
end

但是,此时,您还可以使用Proc.new将块分配给变量。

def say_hello(name)
  block = block_given? ? Proc.new : ->(name) { puts "Hi, #{name}" }
  block.call(name)
end

最后,我试图理解这种方法何时才有意义。在大多数情况下,您可以将代码包装在类或模块中,并将其作为参数传递。这可能更好。

答案 1 :(得分:1)

你可以用普通的lambdas来做。

def say_hello(name, block = ->(name) { puts "Hi, #{name}" })
  block.call(name)
end 

say_hello("Sergio")
say_hello("Ivan", ->(name) { puts "Where are you from, #{name}?"})
# >> Hi, Sergio
# >> Where are you from, Ivan?

不确定是否可以使用块执行此操作。块不是普通参数。

答案 2 :(得分:1)

不,您无法在方法定义中提供默认块值。但是,您可以通过在方法体内使用block_given?来实现等效行为,如下所示:

def say_hello(name, &block)
  block = ->(name) { puts "Hi, #{name}" } unless block_given?
  # do something
end

但是,在这种情况下,您无法利用yield来调用传入的任何块,因为在默认情况下它不会存在。您必须调用block Proc对象,例如block.(name)

答案 3 :(得分:1)

有些答案建议使用block_given?,但由于在给出时块不可能是nilfalse,因此您只需使用||=

def say_hello(name, &block)
  block ||= ->(name){puts "Hi, #{name}"}
  # do something
end