【问题标题】:How to convert method or lambda to non-lambda proc如何将方法或 lambda 转换为非 lambda proc
【发布时间】:2013-04-18 07:18:46
【问题描述】:

如下面的 ruby​​ 示例所示,我不能调用带有错误数量的参数的 lambda,因为它对参数数量非常严格:

# method with no args
def a; end

instance_eval(&method(:a))
# ArgumentError: wrong number of arguments (1 for 0)

method(:a).to_proc.call(1, 2, 3)
# ArgumentError: wrong number of arguments (3 for 0)

method(:a).to_proc.lambda?
# => true

如何从ProcMethod 获得不是lambda 的Proc

【问题讨论】:

  • 据我所知,您不能将方法或 lambda 转换为非 lambda proc。你想完成什么?
  • @WallyAltman 块的调用语义,首先是关于参数的数量,但还有其他一些区别。

标签: ruby lambda proc


【解决方案1】:

没有办法做到这一点。

除了参数传递之外,我想知道您对方法中的return 有什么期望。它只能以lambda 方式运行...

如果你真的必须这样做,你将需要构建自己的块,例如

Proc.new{ a }

对于更通用的方法,您必须检查方法的arity 并仅传递所需的参数。

【讨论】:

  • 我想这不太可能因为returnnextbreak,作为临时措施,我要么用 splat 编写方法,要么让它们返回 Proc。有没有办法证明做不到?
  • @michelpm:没有证据,抱歉。
【解决方案2】:

尝试将其包装在非 lambda Proc 中,如下所示:

l = lambda {|a,b| puts "a: #{a}, b: #{b}" }
p = proc {|a,b| l.call(a,b) }

l.lambda?
#=> true
l.arity
#=> 2
l.call("hai")
#=> ArgumentError: wrong number of arguments (1 for 2)
l.call("hai", "bai", "weee", "womp", "woo")
#=> ArgumentError: wrong number of arguments (5 for 2)

p.lambda?
#=> false
p.arity
#=> 2
p.call("hai")
#=> a: hai, b: 
p.call("hai", "bai", "weee", "womp", "woo")
#=> a: hai, b: bai

【讨论】:

    【解决方案3】:

    Lambda 转换为Proc

    这是一种解决方法,它在 Proc 中包装了 lambdamethod 调用,并使用 splat 处理任意数量的参数:

    def lambda_to_proc(lambda)
      Proc.new do |*args|
        diff = lambda.arity - args.size
        diff = 0 if diff.negative?
        args = args.concat(Array.new(diff, nil)).take(lambda.arity)
    
        lambda.call(*args)
      end
    end
    

    无论传递多少参数,这总是有效的;额外的参数将被删除,nil 将替换缺少的参数。


    示例:

    # lambda with two args
    some_lambda = -> (a,b) { [a, b] }
    
    # method with no args
    def some_method; "hello!"; end
    
    lambda_to_proc(some_lambda).call(5)
    # => [5, nil]
    
    lambda_to_proc(method(:some_method)).call(1,2,3)
    # => "hello!"
    

    注意:没有直接的方法可以将 lambda 或方法调用转换为 proc。这只是一种解决方法,显然比真正的交易慢(因为将一个调用包装在另一个调用中)。

    【讨论】:

    • 请记住,如果您的 lambda 可以采用默认参数,这将不起作用。例如。 some_lambda = -> (a, b = 0) { [a, b] } 在使用 lambda_to_proc 调用时会引发 ArgumentError。一种解决方法是使用lambda.parameters.length 而不是lambda.arity
    猜你喜欢
    • 2011-02-26
    • 2022-12-18
    • 2020-10-23
    • 2016-09-23
    • 1970-01-01
    • 2010-09-08
    • 1970-01-01
    • 2020-08-21
    • 1970-01-01
    相关资源
    最近更新 更多