[英]Is it possible to declare a method with block as default value?
I want to write a method which takes a block and if no block given it should use a default block. 我想编写一个方法,该方法需要一个块,如果没有给出块,则应使用默认块。 So I want to have something like this:
所以我想要这样的东西:
def say_hello(name, &block = ->(name) { puts "Hi, #{name}" })
# do something
end
But when I'm trying to do so I'm getting the syntax error. 但是,当我尝试这样做时,出现语法错误。
I know I can deal with my problem using block_given?
我知道我可以使用
block_given?
处理我的问题block_given?
. 。 But I am interested in first approach.
但是我对第一种方法感兴趣。 Am I missing something or this is just not possible?
我是否缺少某些东西,或者这根本不可能?
You cannot declare a default block in the method definition, however you can use a little trick to use a custom block if none is given. 您不能在方法定义中声明默认块,但是如果未给出自定义块,则可以使用一些技巧来使用自定义块。
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!
Let me explain it a little bit. 让我解释一下。 Let's start from a more readable version.
让我们从更具可读性的版本开始。
def say_hello(name, &block)
block = block ? block : ->(name) { puts "Hi, #{name}" }
block.call(name)
end
You define the method to accept a block, then you check if block is defined. 您定义接受块的方法,然后检查是否定义了块。 If not, you assign a custom block.
如果不是,则分配一个自定义块。 Finally, you execute the block.
最后,执行该块。
Let's enhance it a little bit. 让我们对其进行一些增强。 You can use block_given?
您可以使用block_given吗? to check if a block is passed
检查是否通过了块
def say_hello(name, &block)
block = block_given? ? block : ->(name) { puts "Hi, #{name}" }
block.call(name)
end
This also allows you to skip the declaration of the block ( &block
) in the method definition. 这还允许您跳过方法定义中的块声明(
&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
But, at this point, you can also use the Proc.new
to assign the block to a variable. 但是,此时,您还可以使用
Proc.new
将块分配给变量。
def say_hello(name)
block = block_given? ? Proc.new : ->(name) { puts "Hi, #{name}" }
block.call(name)
end
As a final word, I'm trying to understand when this approach would make sense. 最后,我试图了解这种方法何时可行。 In most cases, you can probably wrap the code in a class or module and pass it as argument.
在大多数情况下,您可以将代码包装在类或模块中,并将其作为参数传递。 It's probably better.
可能更好。
You can do it with regular lambdas. 您可以使用常规Lambda做到这一点。
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?
Not sure if you can do this with blocks, though. 不过,不确定是否可以使用块执行此操作。 A block is not an ordinary parameter.
块不是普通参数。
No, you can't provide a default block value in a method definition. 不可以,您不能在方法定义中提供默认的块值。 You can, however, achieve the equivalent behavior through the use of
block_given?
但是,您可以通过使用
block_given?
实现相同的行为block_given?
within the body of the method, as follows: 在方法主体内,如下所示:
def say_hello(name, &block)
block = ->(name) { puts "Hi, #{name}" } unless block_given?
# do something
end
However, in this scenario you can't utilize yield
to invoke any block that is passed in, since it won't be there in the default case. 但是,在这种情况下,您不能利用
yield
来调用传入的任何块,因为在默认情况下它将不存在。 You'll have to invoke the block
Proc
object, as in block.(name)
. 您必须像
block.(name)
一样调用block
Proc
对象。
Some answers suggest using block_given?
一些答案建议使用
block_given?
, but since there is no possibility that a block would be nil
or false
when it is given, you can simply use ||=
. ,但是由于块在给出时不可能为
nil
或false
,因此您可以简单地使用||=
。
def say_hello(name, &block)
block ||= ->(name){puts "Hi, #{name}"}
# do something
end
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.