在Ruby中传递一个方法作为参数
我正在试图用Ruby来解决一些问题。 为此,我尝试从“Programming Collective Intelligence”Ruby这本书中实现这些algorithm(Python中给出的)。
在第8章中,作者通过一个方法a作为参数。 这似乎在Python中工作,但不是在Ruby中。
我在这里有这个方法
def gaussian(dist, sigma=10.0) foo end
并想用另一种方法调用此方法
def weightedknn(data, vec1, k = 5, weightf = gaussian) foo weight = weightf(dist) foo end
我得到的只是一个错误
ArgumentError: wrong number of arguments (0 for 1)
你想要一个proc对象:
gaussian = Proc.new do |dist, *args| sigma = args.first || 10.0 ... end def weightedknn(data, vec1, k = 5, weightf = gaussian) ... weight = weightf.call(dist) ... end
只要注意,你不能像这样的块声明中设置一个默认的参数。 所以你需要使用splat并在proc代码中设置默认值。
或者,根据所有这些的范围,可能会更容易传入方法名称。
def weightedknn(data, vec1, k = 5, weightf = :gaussian) ... weight = self.send(weightf) ... end
在这种情况下,您只是调用在对象上定义的方法,而不是传入完整的代码块。 根据你的结构,你可能需要用object_that_has_the_these_math_methods.send
replaceself.send
最后但并非最不重要的是,您可以挂掉方法。
def weightedknn(data, vec1, k = 5) ... weight = if block_given? yield(dist) else gaussian.call(dist) end end ... end weightedknn(foo, bar) do |dist| # square the dist dist * dist end
但是,这听起来像你想在这里更多的可重用的代码块。
引用块和Proc的注释是正确的,因为它们在Ruby中更常见。 但是如果你愿意,你可以传递一个方法。 你调用method
来获取方法和.call
来调用它:
def weightedknn( data, vec1, k = 5, weightf = method(:gaussian) ) ... weight = weightf.call( dist ) ... end
你可以通过method(:function)
方式传递一个方法作为参数。 贝娄一个非常简单的例子:
def double(a) 返回一个* 2 结束 =>零 def method_with_function_as_param(callback,number) callback.call(数字) 结束 =>零 method_with_function_as_param(方法(:double),10) => 20
正常的Ruby方法是使用块。
所以它会是这样的:
def weightedknn( data, vec1, k = 5 ) foo weight = yield( dist ) foo end
并用于:
weightenknn( data, vec1 ) { |dist| gaussian( dist ) }
这种模式在Ruby中被广泛使用。
您可以在Method
实例上使用&
运算符将该Method
转换为块 。
例:
def foo(arg) p arg end def bar(&block) p 'bar' block.call('foo') end bar(&method(:foo))
有关详情, 请访问http://weblog.raganwald.com/2008/06/what-does-do-when-used-as-unary.html
你必须调用函数对象的方法“调用”:
weight = weightf.call( dist )
编辑:正如评论中所解释的,这种做法是错误的。 这将工作,如果你使用Procs而不是普通的function。
我build议使用&符号来访问函数中的命名块。 按照这篇文章给出的build议,你可以写这样的东西(这是我的工作程序中的一个真正的废品):
# Returns a valid hash for html form select element, combined of all entities # for the given +model+, where only id and name attributes are taken as # values and keys correspondingly. Provide block returning boolean if you # need to select only specific entities. # # * *Args* : # - +model+ -> ORM interface for specific entities' # - +&cond+ -> block {|x| boolean}, filtering entities upon iterations # * *Returns* : # - hash of {entity.id => entity.name} # def make_select_list( model, &cond ) cond ||= proc { true } # cond defaults to proc { true } # Entities filtered by cond, followed by filtration by (id, name) model.all.map do |x| cond.( x ) ? { x.id => x.name } : {} end.reduce Hash.new do |memo, e| memo.merge( e ) end end
AfterWork,你可以这样调用这个函数:
@contests = make_select_list Contest do |contest| logged_admin? or contest.organizer == @current_user end
如果你不需要过滤你的select,你只需要忽略这个块:
@categories = make_select_list( Category ) # selects all categories
Ruby块的力量非常重要。
您也可以使用“eval”,并将该方法作为stringparameter passing,然后在另一个方法中简单地对其进行评估。