gpt4 book ai didi

ruby - 是否可以将参数绑定(bind)到(一元)Proc 对象?

转载 作者:数据小太阳 更新时间:2023-10-29 07:58:46 27 4
gpt4 key购买 nike

(交叉贴:一周前我已经在 Ruby Forum 上问过这个问题,但还没有得到任何回复)。

这是我目前拥有的(非常)简化的工作版本:

# A class S with two methods, one which requires one parameter, and
# one without parameters.
class S
def initialize(s); @ms = s; end
def s_method1(i); puts "s_method1 #{i} #{@ms}"; end
def s_method2; puts "s_method2 #{@ms}"; end
end

# A class T which uses S, and "associates" itself to
# one of the both methods in S, depending on how it is
# initialized.
class T
def initialize(s, choice=nil)
@s = S.new(s)
# If choice is true, associate to the one-parameter-method, otherwise
# to the parameterless method.
@pobj = choice ? lambda { @s.s_method1(choice) } : @s.method(:s_method2)
end

# Here is how I use this association
def invoke
@pobj.call
end
end

在此示例中,根据 T 的构造方式,T#invoke 调用S#s_method1 或 S#S_method2,但在调用的情况下S#s_method1,s_method1 的参数在创建时已经固定T对象的时间。因此,以下两行,

T.new('no arguments').invoke
T.new('one argument', 12345).invoke

产生输出

s_method2 no arguments
s_method1 12345 one argument

这正是我需要的。

现在回答我的问题:

在这种情况下,choicenil,即我想调用无参数方法 s_method2,我可以在一个优雅的方式

@s.method(:s_method2)

如果 choice 不是nil,我必须构造一个 Proc 对象使用`lambda。这不仅看起来笨拙,而且让我觉得有点不舒服。我们这里有一个闭包,它连接到初始化方法中的环境,我不确定这是否在某些情况下可能会导致内存泄漏,从而引起麻烦。

有没有一种简单的方法来简单地绑定(bind)一个方法对象(在这种情况下@s.method(:s_method1) 到固定参数?

我的第一个想法是使用

@s.method(:s_method1).curry[choice]

但这并没有达到我的目的。它不会返回可调用的 Proc 对象,而是实际执行 s_method1(这不是错误,而是有记录的行为)。

关于如何实现我的目标还有其他想法吗?

最佳答案

单独保存参数

这个选项很简单,但它可能不是您要找的:

class T
def initialize(s, choice=nil)
s = S.new(s)
@choice = choice
@pobj = s.method(choice ? :s_method1 : :s_method2)
end

def invoke
@pobj.call(*@choice)
end
end

T.new('no arguments').invoke
T.new('one argument', 12345).invoke
#=> s_method2 no arguments
#=> s_method1 12345 one argument

默认参数的方法改进(Ruby 2.0+)

# Allows setting default parameters for methods, after they have been defined.
module BindParameters
refine Method do
def default_parameters=(params)
@default_params = params
end

def default_parameters
@default_params || []
end

alias_method :orig_call, :call

def call(*params)
merged_params = params + (default_parameters[params.size..-1] || [])
orig_call(*merged_params)
end
end
end

这是一个例子:

def f(string)
puts "Hello #{string}"
end

def g(a, b)
puts "#{a} #{b}"
end

using BindParameters

f_method = method(:f)
f_method.default_parameters = %w(World)

f_method.call('user') # => Hello user
f_method.call # => Hello World

g_method = method(:g)
g_method.default_parameters = %w(Hello World)

g_method.call # => Hello World
g_method.call('Goodbye') # => Goodbye World
g_method.call('Goodbye', 'User') # => Goodbye User

您的代码可以重写:

class T
using BindParameters
def initialize(s, *choice)
s = S.new(s)
@pobj = s.method(choice.empty? ? :s_method2 : :s_method1)
@pobj.default_parameters = choice
end

def invoke
@pobj.call
end
end

T.new('no arguments').invoke # => s_method2 no arguments
T.new('one argument', 12_345).invoke # => s_method1 12345 one argument

Monkey-Patching Method 类(Ruby 1.9+)

如果修补方法类是可以接受的,您可以使用:

class Method 
def default_parameters=(params)
@default_params = params
end

def default_parameters
@default_params || []
end

alias_method :orig_call, :call

def call(*params)
merged_params = params + (default_parameters[params.size..-1] || [])
orig_call(*merged_params)
end
end

T 变成:

class T
def initialize(s, *choice)
s = S.new(s)
@pobj = s.method(choice.empty? ? :s_method2 : :s_method1)
@pobj.default_parameters = choice
end

def invoke
@pobj.call
end
end

包装方法类(Ruby 1.9+)

如果你不想污染方法类,这种方式可能更干净:

class MethodWithDefaultParameters
attr_accessor :default_parameters
attr_reader :method

def initialize(receiver, method_symbol)
@method = receiver.public_send(:method, method_symbol)
@default_parameters = []
end

def call(*params)
merged_params = params + (default_parameters[params.size..-1] || [])
method.call(*merged_params)
end

def method_missing(sym, *args)
method.send(sym, *args)
end
end

T 变成:

class T
def initialize(s, *choice)
s = S.new(s)
@pobj = MethodWithDefaultParameters.new(s, choice.empty? ? :s_method2 : :s_method1)
@pobj.default_parameters = choice
end

def invoke
@pobj.call
end
end

欢迎任何意见或建议!

关于ruby - 是否可以将参数绑定(bind)到(一元)Proc 对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41116975/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com