最近我遇到了使用方法调用的some code,其格式为object.(arg1, arg2)
,但没有看到一个好的解释它是如何工作的。请看这个示例代码:
class TestServiceObject
def call
'method'
end
end
TestServiceObject.new.()
# => 'method'
这种速记方式的术语是什么?
最近我遇到了使用方法调用的some code,其格式为object.(arg1, arg2)
,但没有看到一个好的解释它是如何工作的。请看这个示例代码:
class TestServiceObject
def call
'method'
end
end
TestServiceObject.new.()
# => 'method'
点括号表示法是一种缩写方式,用于将参数传递给 Ruby 对象上的隐式 call
方法:
foo = lambda {|bar| puts bar}
foo.call('baz')
#=> baz
foo.('baz')
foo.call('baz') === foo.('baz')
#=> true
还要注意以下符号也是有效的(且等效于)调用 call
方法:
Also note that the following notations are also valid (and equivalent) invocations of the call
method:
foo['baz']
#=> baz
foo::('baz')
#=> baz
在您的示例中,您明确地覆盖了TestServiceObject
类上的call
方法,以便在调用时返回字符串'method'
。因此,您可以明确地覆盖call
方法以接受参数:
class TestServiceObject
def call(foo=nil)
foo || 'method'
end
end
TestServiceObject.new.()
#=> method
TestServicesObject.new.('bar')
#=> bar
更新:
正如评论者@LoganSerman所指出的那样,缩写运算符似乎可以用于任何响应call
的对象,这在以下示例中得到验证:
m = 12.method("+")
m.call(3)
#=> 15
m.(3)
#=> 15
更新2:
正如评论者@Stefan从在Proc#call
文档中指出的:
prc.()调用给定参数的prc.call()。 这是一种语法糖,用于隐藏“call”。
m[3]
和作用域解析运算符 m::(3)
调用 call
。 - Stefancall
方法。”- 这是错误的。call
并非 Ruby 中的隐式方法。Ruby 没有隐式方法。您可能在想 Scala,这是我所知道的唯一具有隐式的语言。 - Jörg W Mittagcall
方法:foo['baz']
。这是错误的:索引运算符转换为对[]
方法的调用,而不是对call
方法的调用。foo['baz']
等同于foo.[]('baz')
,而不是foo.call('baz')
。 - Jörg W Mittaga_proc[arg]
被翻译为 a_proc.[](arg)
,而不是 a_proc.call(arg)
。[]
索引运算符的翻译不会因对象类型的不同而自动改变,它总是被翻译成调用 []
方法,而不是 call
方法,无论对象是 Array
、Hash
、Proc
还是 FooBarFrobnicatorThingamajingy
。 - Jörg W Mittagfoo.(bar, baz)
被解释为
foo.call(bar, baz)
就像
foo + bar
被解释为
foo.+(bar)
foo[bar, baz] = quux
被解释为
foo.[]=(bar, baz, quux)
这个设计的目的是让调用类似函数的对象看起来像调用方法:
foo.(bar, baz) # function
foo(bar, baz) # method
o = Object.new
def o.call(*args); "`call` called with #{args.join(', ')}" end
o.(42)
# => "`call` called with 42"
o[42]
# NoMethodError: undefined method `[]' for #<Object:0xdeadbeefc0ffee>
def o.[](*args); "`[]` called with #{args.join(', ')}" end
o[42]
# => "`[]` called with 42"
obj.(args)
只是解析器提供的一个功能。从技术上讲,它不是别名,但它仅仅具有在定义了call方法的对象上调用obj.call(args)
时相同的效果。