Как работает оператор 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 метод.

Другие вопросы по тегам