Ruby只向lambda传递预期数量的参数的捷径

2w3rbyxf  于 11个月前  发布在  Ruby
关注(0)|答案(2)|浏览(95)

下面的代码是否有一个捷径,只将预期数量的参数(“arity”)传递给lambda(而忽略其余的)?

args = [:p1, :p2, :p3, :p4, :p5, :p6]
expected_args = args[0...the_lambda.arity]
value = the_lambda.call(*expected_args)

字符串
我写了一个Ruby程序,用户可以写一个Ruby配置文件,其中包含了一些参数,我希望用户能够只使用所需的参数来写这些参数(而不必做“额外”的输入,比如包含不会使用的参数)。
使用上面的代码,用户可以编写

my_override = ->(a) {....}


my_override = ->(a, b, c) { ....}


编译器也不会抱怨。(这里的部分想法是,当教授新用户时,我们甚至不需要提及存在多于一个或两个参数的事实。我们可以简单地“保存”那些额外的特性,以便向更高级的用户显示。)最终目标是尽可能简单地编写用户名--这意味着避免使用用户的元素--不直接对lambda函数起作用的书面代码。

o7jaxewo

o7jaxewo1#

从定义上讲,Ruby中的lambda对象关心arity,但Proc对象不关心。你可以对lambda做一些类似splat参数的事情(我在下面提供了一个这样的例子),但无论是Proc还是lambda,你都需要添加逻辑来处理调用者做了一些意外的事情。这在方法中比在Proc或lambda中容易得多。
一般来说,避免arity问题的正确做法是使用Proc对象,因为Proc不关心arity。例如,无论传入一个Array还是多个Array对象,这都可以正常工作:

prc = proc { |a, b| pp a, b }

prc.call [1, 2, 3, 4, 5]
#=> [1, 2]

prc.call 1, 2, 3, 4, 5
#=> [1, 2]

字符串
否则,你将需要与你的调用者更紧密地合作(这通常是糟糕的设计),或者创建一个splarted参数只是为了扔掉位置参数。例如:

# define +prc+ as a lambda and then coerce it
prc = ->(*ary) { pp ary.flatten.take(2) }

prc.call [1, 2, 3, 4, 5]
#=> [1, 2]

prc.call 1, 2, 3, 4, 5
#=> [1, 2]


无论哪种方式,你都有边缘情况。考虑一下:

prc = proc { |a, b| pp a, b }
prc.call [1, 2, 3, 4, 5], [6, 7]
#=> [[1, 2, 3, 4, 5], [6, 7]]

prc = ->(*ary) { pp ary.flatten.take(2) }
prc.call [1, 2, 3, 4, 5], [6, 7]
# => [1, 2]


如果你不知道调用者可能会传入什么,你可以写一个方法,这样你就可以处理arity,关键字选项,duck-typing,类验证,或者任何其他你需要验证未知输入的健全性检查。如果你需要一个闭包,Proc对象和proximal可能很有用。但是除了关闭定义它们的绑定之外,我不确定与这将为您的特定用例带来的麻烦相比,您获得了什么。

zvokhttg

zvokhttg2#

一般来说,我同意使用Proc或选项Hash的评论,但您可以通过 Package “user lambda”和传入方法调用的参数来简化请求,如下所示

def lambda_wrapper(user_lambda,*args,**kwargs,&block)
  defined_args = user_lambda.parameters
     .each_with_object(Hash.new {|h,k| h[k] = []}) do |(type,arg),obj| 
       obj[type] << arg
     end
  user_lambda.call(
    *collect_args(args,defined_args),
    **collect_kwargs(kwargs,defined_args),
    &block)
end

def collect_args(args, defined_args)
  return args if defined_args.key?(:rest)
  args.first(defined_args[:req].concat(defined_args[:opt]).size)
end

def collect_kwargs(kwargs, defined_args)
  return kwargs if defined_args.key?(:keyrest)
  kwargs.slice(*defined_args[:keyreq].concat(defined_args[:key]))
end

字符串
虽然我建议在一个类中实现这个功能(工作示例),但这将收集lambda的参数和关键字参数,然后通过从传递给 Package 器的参数中提取这些参数来调用用户lambda。
范例:

user_lambda = ->(a,b,c,d=57, e:, f:,g:92) {[a,b,c,d,e,f,g]}
lambda_wrapper(user_lambda,1,2,3,e:12,f:17)
#=> [1,2,3,57,12,17,92]
lambda_wrapper(user_lambda,1,2,3,4,e:12,f:17,g:101)
#=> [1,2,3,4,12,17,101]
lambda_wrapper(user_lambda,1,2,3,4,5,6,e:12,f:17,x:88)
#=> [1,2,3,4,12,17,92]
lambda_wrapper(user_lambda,1,2,e:12,f:17,x:88)
#=> wrong number of arguments (given 2, expected 3+; required keywords: e, f) (ArgumentError)
lambda_wrapper(user_lambda,1,2,3,f:17,x:88)
#=> missing keyword: :e (ArgumentError)

相关问题