如何在 Ruby 中预填充函数的参数?
How to pre-fill arguments to a function in Ruby?
假设我有一个函数 foo:
def foo(A, B, C)
A + B + C
end
我这样称呼它,只更改最后一个参数:
foo("foo", "bar", "123")
foo("foo", "bar", "456")
foo("foo", "bar", "789")
如何“烘焙”或“预填充”不更改的参数?所以也许我会得到一个新的可调用 foo_baked
使得 foo_baked("123")
与 foo("foo", "bar", "123")
?
相同
并像这样使用它:
foo_baked = ...?
foo_baked("123")
foo_baked("456")
foo_baked("789")
请注意,我不想使用 def
定义新函数,但希望能够在运行时动态创建 foo_baked,也许是一个数组。
您可以定义一个新方法 foo_baked
来包装 foo
并将 non-changeable 参数作为硬编码值传递:
def foo_baked(c)
foo("foo", "bar", c)
end
然后可以这样调用:
foo_baked("123")
或者,您可以使用 Ruby 的 built-in #curry
方法,如 中所述。这种方法更灵活,返回一个可调用的过程,直到提供足够的参数。
你有几个选择。第一种是 Zoran 的回答中概述的 currying 方法。
第二种是使用默认位置参数。但为了做到这一点,可选参数需要 在 所需参数之后:
def foo_baked(a, b="foo", c="bar")
[a, b, c]
end
foo_baked(123) # => [123, "foo", "bar"]
foo_baked(123, "asd")
第三个选项是使用关键字参数。这种方法的好处是参数可以按任何顺序排列。您可以挑选并选择您为其提供值的那些。
def foo_baked(b: "foo", c: "bar", a:)
[a, b, c]
end
foo_baked(a: 123) # => [123, "foo", "bar"]
foo_baked(a: 123, b: "asd") # => [123, "asd", "bar"]
最后一个选择是结合位置参数和关键字参数:
def foo_baked(a, b: "foo", c: "bar")
[a, b, c]
end
foo_baked(123) # => [123, "foo", "bar"]
foo_baked(123, b: "asd") # => [123, "asd", "bar"]
这样做的好处是您仍然可以使用位置参数,但可选参数的顺序无关紧要,它们永远不会干扰位置参数
您可以创建一个 lambda 包装原始方法:
foo_baked = ->(value) { foo('foo', 'bar', value) }
foo_baked.(123) # => [123, "foo", "bar"]
请注意执行过程中的附加 .
。这是ruby特殊语法,相当于:
foo_baked.call(123)
Ruby 有 function-currying built in with the curry 方法:
def foo(a, b, c)
a + b + c
end
foo_baked = method(:foo).curry.call('foo', 'bar')
# this returns "foobar123"
foo_baked.call('123')
# ArgumentError (wrong number of arguments (given 4, expected 3))
foo_baked.call('123', '234')
基本上,Method#curry
returns curried proc:一个函数,pre-loaded 带有参数,只有在传递了足够的参数以满足方法签名后才会执行。
注意 foo_baked.lambda?
returns true
,所以柯里化过程是 actually a lambda。这很重要,因为这意味着如果您超过参数的最大数量,您将获得 ArgumentError
。
您可以通过将 arity 参数传递给 curry
.
来允许超出所需三个参数的其他参数
def foo(*args)
args.join
end
# does not execute since only 2 arguments have been supplied
foo_baked = method(:foo).curry(3).call('foo', 'bar')
# executes on the third argument
# this returns "foobar123"
foo_baked.call('123')
# this returns "foobar123234"
foo_baked.call('123', '234')
假设我有一个函数 foo:
def foo(A, B, C)
A + B + C
end
我这样称呼它,只更改最后一个参数:
foo("foo", "bar", "123")
foo("foo", "bar", "456")
foo("foo", "bar", "789")
如何“烘焙”或“预填充”不更改的参数?所以也许我会得到一个新的可调用 foo_baked
使得 foo_baked("123")
与 foo("foo", "bar", "123")
?
并像这样使用它:
foo_baked = ...?
foo_baked("123")
foo_baked("456")
foo_baked("789")
请注意,我不想使用 def
定义新函数,但希望能够在运行时动态创建 foo_baked,也许是一个数组。
您可以定义一个新方法 foo_baked
来包装 foo
并将 non-changeable 参数作为硬编码值传递:
def foo_baked(c)
foo("foo", "bar", c)
end
然后可以这样调用:
foo_baked("123")
或者,您可以使用 Ruby 的 built-in #curry
方法,如
你有几个选择。第一种是 Zoran 的回答中概述的 currying 方法。
第二种是使用默认位置参数。但为了做到这一点,可选参数需要 在 所需参数之后:
def foo_baked(a, b="foo", c="bar")
[a, b, c]
end
foo_baked(123) # => [123, "foo", "bar"]
foo_baked(123, "asd")
第三个选项是使用关键字参数。这种方法的好处是参数可以按任何顺序排列。您可以挑选并选择您为其提供值的那些。
def foo_baked(b: "foo", c: "bar", a:)
[a, b, c]
end
foo_baked(a: 123) # => [123, "foo", "bar"]
foo_baked(a: 123, b: "asd") # => [123, "asd", "bar"]
最后一个选择是结合位置参数和关键字参数:
def foo_baked(a, b: "foo", c: "bar")
[a, b, c]
end
foo_baked(123) # => [123, "foo", "bar"]
foo_baked(123, b: "asd") # => [123, "asd", "bar"]
这样做的好处是您仍然可以使用位置参数,但可选参数的顺序无关紧要,它们永远不会干扰位置参数
您可以创建一个 lambda 包装原始方法:
foo_baked = ->(value) { foo('foo', 'bar', value) }
foo_baked.(123) # => [123, "foo", "bar"]
请注意执行过程中的附加 .
。这是ruby特殊语法,相当于:
foo_baked.call(123)
Ruby 有 function-currying built in with the curry 方法:
def foo(a, b, c)
a + b + c
end
foo_baked = method(:foo).curry.call('foo', 'bar')
# this returns "foobar123"
foo_baked.call('123')
# ArgumentError (wrong number of arguments (given 4, expected 3))
foo_baked.call('123', '234')
基本上,Method#curry
returns curried proc:一个函数,pre-loaded 带有参数,只有在传递了足够的参数以满足方法签名后才会执行。
注意 foo_baked.lambda?
returns true
,所以柯里化过程是 actually a lambda。这很重要,因为这意味着如果您超过参数的最大数量,您将获得 ArgumentError
。
您可以通过将 arity 参数传递给 curry
.
def foo(*args)
args.join
end
# does not execute since only 2 arguments have been supplied
foo_baked = method(:foo).curry(3).call('foo', 'bar')
# executes on the third argument
# this returns "foobar123"
foo_baked.call('123')
# this returns "foobar123234"
foo_baked.call('123', '234')