将函数传递给另一个函数,并将其称为
Ruby中的函数不是第一类对象,但我希望能够将对函数的引用传递给另一个函数并使其执行。如何才能做到这一点?将函数传递给另一个函数,并将其称为
例子:
def run_a_function_twice(my_function)
# Call the function once.
# Call the function again.
end
def say_hello
puts "HI!"
end
run_a_function_twice(say_hello)
我读的文档,但不知道我是否应该尝试lambda表达式,特效,或拨打电话(我只熟悉从其他语言调用的概念)
您可以用两种不同的方式做到这一点:
-
传递方法的名称(通常为一个符号,而是一个字符串,将工作太):
def run_a_method_twice(method_name) send(method_name) send(method_name) end run_a_method_twice(:say_hello)
这取决于
say_hello
感可在与run_a_method_twice
相同的范围内获得,例如如果它们都是同一类的实例方法。如果在另一个对象上定义了say_hello
,则可以执行some_obj.send(:say_hello)
。您可以通过在方法名后面提供
send
来为方法提供参数,例如,jordan.send(:say_hello, "Donny")
。 -
使用块:
def yield_to_a_block_twice yield yield end yield_to_a_block_twice { say_hello }
这句法的作品,以及:
def call_a_block_twice(&block) block.call block.call end
你应该使用
yield
可能时(它的速度更快),但有时是必要的,以便能够指(例如,如果您需要将它传递给另一个方法,或者从另一个块内调用它),在这种情况下,使其成为命名参数(即def meth(arg1, arg2, &block_name)
)是必要的。Block,Proc和lambda之间的区别对Ruby新手来说很具挑战性,并且大部分都是关于它们的 - 只是谷歌“Ruby block proc lambda”。这里有一个很好的文章,让您开始:http://awaxman11.github.io/blog/2013/08/05/what-is-the-difference-between-a-block/
这是通过块传递方法完成的。这有几种语法。
第一个语法使用yield,看起来像这样。
def method1
puts "This is from method 1"
yield
end
def method2
puts "This is from method 2"
end
method1(){method2}
上面将输出
这是从方法1
这是来自方法2
第二种选择使用以下语法
def method1(&block)
puts "This is from method 1"
block.call
end
def method2
puts "This is from method 2"
end
method1(){method2}
输出t结果是一样的。典型地,yield
语法是优选的,因为它更简洁,但也因为它的平均速度约为标记的5倍。
第三个选项是使用send
语法,如下所示。
def method1(method_name_string)
puts "This is from method 1"
send(method_name_string, 1, 2)
end
def method2(a,b)
puts "This is from method 2" + a.to_s + ' ' + b.to_s
end
method1("method2")
您也可以使用lambda
或Proc.new
def method1(lmb)
puts "This is from method 1"
block.call "A string"
end
foo = lambda do |x|
puts x
end
method1(foo)
在这种情况下实现类似的东西,你会看到
这是从方法1
的字符串
一般在Ruby中,它们是匿名方法(闭包),如果你愿意块的概念。
您可以将块传递给任何方法。该方法可以使用yield
(与block_given?
一起)调用方法/块,或者使用&
运算符将其引用到变量。后者可用于存储引用或将其传递给另一种方法。
def call_it_twice
2.times {|i| yield(i) }
end
call_it_twice { puts "hello" }
# hello
# hello
call_it_twice {|i| puts "hello #{i}" }
# hello 0
# hello 1
def call_it_thrice &block
call_it_twice(&block)
block.call(2)
end
call_it_thrice {|i| puts "hello #{i}" }
# hello 0
# hello 1
# hello 2
您也可以传递一个文字方法,但它并不常见。
class Foo
def hello
puts "world"
end
end
Foo.instance_methods(:hello)
# #<UnboundMethod: Foo#hello>
Foo.instance_method(:hello).call
# NoMethodError: undefined method `call' for #<UnboundMethod: Foo#hello>
Foo.instance_method(:hello).bind(Foo.new).call
# world
Foo.new.method(:hello)
# #<Method: Foo#hello>
Foo.new.method(:hello).call
# world
常见的事是写array.map{|x| x.downcase }
为array.map(&:downcase)
(这是to_proc
快捷方式,以便它array.map(&:downcase.to_proc)
幕后)。
比较陌生,虽然是这样的:array.each{|x| puts x }
是一样的Ruby array.each(&method(:puts))
函数不是第一类对象...
这只是是不正确的。首先,Ruby没有真的有有功能。当你定义一个“函数”时,Ruby实际上将一个实例方法添加到Object
。这与定义一个函数的效果相同,因为一切都是一个对象,因此该方法总是可以被调用。
其次,方法是第一类对象,他们只是有点难以访问,因为Ruby总是认为你想调用方法而不是直接访问方法对象。 method
方法让你成为对象。
def run_a_function_twice(my_function)
2.times { my_function.() }
end
def say_hello
puts "HI!"
end
run_a_function_twice(method(:say_hello))
感谢您的回答最大!你如何使用'my_function。()'而不是'my_function.call()'? – 2014-10-17 20:42:33
没有特别的理由。它做同样的事情,只是更短。 – Max 2014-10-17 20:45:09