我想编写一个接受块的方法,如果没有给定块,则应使用默认块。所以我希望有这样的东西:
def say_hello(name, &block = ->(name) { puts "Hi, #{name}" })
# do something
end
但是当我尝试这样做时,我收到了语法错误。
我知道我可以使用block_given?
处理我的问题。但我对第一种方法感兴趣。
我错过了什么或者这是不可能的吗?
答案 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?
,但由于在给出时块不可能是nil
或false
,因此您只需使用||=
。
def say_hello(name, &block)
block ||= ->(name){puts "Hi, #{name}"}
# do something
end