Ruby的.()操作符是如何工作的?

38

最近我遇到了使用方法调用的some code,其格式为object.(arg1, arg2),但没有看到一个好的解释它是如何工作的。请看这个示例代码:

class TestServiceObject
  def call
    'method'
  end
end

TestServiceObject.new.()
# => 'method'

这种速记方式的术语是什么?

1
这个答案看起来就是你需要的。以后参考一下,SymbolHound对于查找语言语法非常方便... - Simon M
3个回答

50

点括号表示法是一种缩写方式,用于将参数传递给 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:

正如评论者@StefanProc#call文档中指出的:

prc.()调用给定参数的prc.call()。 这是一种语法糖,用于隐藏“call”。


Proc#call“请注意,prc.()使用给定的参数调用prc.call()。这是一种语法糖,用于隐藏“call”。” - Stefan
为了完整起见,您还可以使用方括号 m[3] 和作用域解析运算符 m::(3) 调用 call - Stefan
1
“点括号符号表示法是一种缩写方式,用于将参数传递给 Ruby 对象上的隐式 call 方法。”- 这是错误的。call 并非 Ruby 中的隐式方法。Ruby 没有隐式方法。您可能在想 Scala,这是我所知道的唯一具有隐式的语言。 - Jörg W Mittag
1
还要注意以下符号也是有效的(且等效于)调用call方法:foo['baz']。这是错误的:索引运算符转换为对[]方法的调用,而不是对call方法的调用。foo['baz']等同于foo.[]('baz'),而不是foo.call('baz') - Jörg W Mittag
1
a_proc[arg] 被翻译为 a_proc.[](arg),而不是 a_proc.call(arg)[] 索引运算符的翻译不会因对象类型的不同而自动改变,它总是被翻译成调用 [] 方法,而不是 call 方法,无论对象是 ArrayHashProc 还是 FooBarFrobnicatorThingamajingy - Jörg W Mittag
显示剩余4条评论

6
foo.(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

尽管其他答案声称与“implicit call method”有关,但这与其无关(Ruby甚至没有隐式方法,只有Scala有)。索引运算符被翻译为不同的方法调用(“[]”),而不是调用“call”。
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"

Ruby... 真是一团糟 :) - Chris

5

obj.(args)只是解析器提供的一个功能。从技术上讲,它不是别名,但它仅仅具有在定义了call方法的对象上调用obj.call(args)时相同的效果。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接