Ruby没有函数,它只有方法(这些方法不是一等公民)和Proc
(一等公民),但不与任何对象相关联。
因此,这是一个方法:
def foo(bar) puts bar end
foo('Hello')
哦,还有,是的,这 确实 是一个方法,而不是顶级函数或过程之类的东西。在顶层定义的方法最终会成为 Object
类中的私有实例方法:
Object.private_instance_methods(false)
这是一个Proc
对象:
foo = -> bar { puts bar }
foo.('Hello')
# Hello
请注意,Proc
的调用方式与方法不同:
foo('Hello') # method
foo.('Hello') # Proc
foo.(bar)
语法只是
foo.call(bar)
的语法糖(对于
Proc
和
Method
也被别名为
foo[bar]
)。在您的对象上实现一个
call
方法,然后使用
.()
调用它是您可以获得类似Python中
__call__
可调用对象的最接近的东西。
请注意,Ruby
Proc
和Python lambda之间的一个重要区别是没有限制:在Python中,lambda只能包含单个语句,但Ruby没有语句和表达式之间的区别(一切都是表达式),因此这种限制根本不存在,在许多情况下,您需要将命名函数作为参数传递给Python,因为您无法在单个语句中表达逻辑,您可以简单地传递
Proc
或块,在Ruby中,这样问题就不会出现丑陋的语法引用方法。
您可以通过在对象上调用
Object#method
方法(这将为您提供其
self
绑定到该特定对象的
Method
)来在
Method
对象中
包装一个方法(本质上是鸭子类型
Proc
)。
foo_bound = method(:foo)
foo_bound.('Hello')
# Hello
你也可以使用Module#instance_method
家族中的方法之一从模块(或类,因为类属于模块)中获取一个UnboundMethod
,然后将其UnboundMethod # bind
到特定对象并调用它。(我认为Python也有相同的概念,尽管实现方式不同:未绑定的方法明确地接受self参数,就像它声明的方式一样。)
foo_unbound = Object.instance_method(:foo) # this is an UnboundMethod
foo_unbound.('Hello')
# NoMethodError: undefined method `call' for #<UnboundMethod: Object#foo>
foo_rebound = foo_unbound.bind(self) # this is a Method
foo_rebound.('Hello')
# Hello
请注意,您只能将UnboundMethod
绑定到来自该方法的模块的实例对象上。您不能使用UnboundMethods
在不相关的模块之间“移植”行为:
bar = module Foo; def bar; puts 'Bye' end; self end.instance_method(:bar)
module Foo; def bar; puts 'Hello' end end
obj = Object.new
bar.bind(obj)
obj.extend(Foo)
bar.bind(obj).()
obj.bar
请注意,无论是
Method
还是
UnboundMethod
都是方法的
包装器,而不是方法本身。在Ruby中,方法不是对象(顺便说一下,这与我在其他答案中写的相反。我真的需要回去修复那些)。你可以将它们
封装到对象中,但它们
不是对象,因为你基本上会遇到所有同样的包装器问题:标识和状态。如果您多次调用相同方法的
method
,每次都会得到不同的
Method
对象。如果你试图在
Method
对象上存储一些状态(例如Python风格的
__doc__
字符串),该状态将对
特定的实例是私有的,如果您尝试通过
method
再次检索文档字符串,您会发现它已经不存在了。
此外,还有一个形式为
方法引用运算符.:
的语法糖:
bound_method = obj.:foo
这与...相同
bound_method = obj.method(:foo)