Как работает оператор Ruby's .()?
Недавно я наткнулся на некоторый код, использующий вызов метода, состоящий из формата object.(arg1, arg2)
не видя хорошего объяснения того, как это работает. Посмотрите этот пример кода:
class TestServiceObject
def call
'method'
end
end
TestServiceObject.new.()
# => 'method'
Какой термин для такого рода сокращений?
3 ответа
Нотация в круглых скобках является сокращенным способом передачи аргументов неявному call
метод на объекте Ruby:
foo = lambda {|bar| puts bar}
foo.call('baz')
#=> baz
foo.('baz')
foo.call('baz') === foo.('baz')
#=> true
Также обратите внимание, что следующие обозначения также являются действительными (и эквивалентными) вызовамиcall
метод:
foo['baz']
#=> baz
foo::('baz')
#=> baz
В вашем примере выявно переопределяетеcall
метод наTestServiceObject
класс такой, что он возвращает строку 'method'
когда звонили. Соответственно, вы можете явно переопределить call
способ принять аргументы:
class TestServiceObject
def call(foo=nil)
foo || 'method'
end
end
TestServiceObject.new.()
#=> method
TestServicesObject.new.('bar')
#=> bar
ОБНОВЛЕНИЕ:
Как Logan Serman комментатор Logan Serman, сокращенный оператор, похоже, работает со всем, что отвечает call
, что подтверждается частично следующим примером:
m = 12.method("+")
m.call(3)
#=> 15
m.(3)
#=> 15
ОБНОВЛЕНИЕ 2:
Как комментатор Stefan также указывает на документацию поProc#call
:
prc. () вызывает prc.call() с заданными параметрами. Это синтаксический сахар, чтобы скрыть "вызов".
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
Несмотря на утверждения в других ответах на этот вопрос, это не имеет ничего общего с 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"
obj.(args)
это просто функция, предоставляемая через анализатор. Технически не псевдоним, но он просто имеет тот же эффект, что и вызов obj.call(args)
на объекте, который определяет call
метод.