ruby & ярлык для to_pro c, кажется, действует нерегулярно - PullRequest
2 голосов
/ 10 апреля 2020

, поэтому я пытаюсь понять, как работает метод sym.to_pro c, предположительно, у любого объекта, который реализует to_pro c, есть сокращение, которое просто является & перед объектом, но поведение этого сокращения выглядит ошибочно c:

это работает

irb(main):022:0> p = :to_s.to_proc
=> #<Proc:0x00000000056c33b0(&:to_s)>

, но это не

irb(main):023:0> p = &:to_s
Traceback (most recent call last):
    3: from X:/Ruby26-x64/bin/irb.cmd:31:in `<main>'
    2: from X:/Ruby26-x64/bin/irb.cmd:31:in `load'
    1: from X:/Ruby26-x64/lib/ruby/gems/2.6.0/gems/irb-1.0.0/exe/irb:11:in `<top (required)>'
SyntaxError ((irb):23: syntax error, unexpected &)
p = &:to_s
    ^

и теперь наоборот, это работает

irb(main):024:0> (0..10).map &:to_s
=> ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]

но это не так!

irb(main):025:0> (0..10).map(:to_s.to_proc)
Traceback (most recent call last):
    5: from X:/Ruby26-x64/bin/irb.cmd:31:in `<main>'
    4: from X:/Ruby26-x64/bin/irb.cmd:31:in `load'
    3: from X:/Ruby26-x64/lib/ruby/gems/2.6.0/gems/irb-1.0.0/exe/irb:11:in `<top (required)>'
    2: from (irb):25
    1: from (irb):25:in `map'
ArgumentError (wrong number of arguments (given 1, expected 0))

эти ошибки, кажется, не имеют смысла, я действительно растерялся.

Ответы [ 2 ]

3 голосов
/ 10 апреля 2020

Амперсанд / оператор с одинарным префиксом & может использоваться в ровно в двух местах:

  • В списке параметров .
  • В списке аргументов .

В списке параметров унарный префикс & ampersand sigil означает «Возьмите переданный блок». в качестве аргумента сверните его в объект Proc и привяжите его к этому параметру. "

В списке аргументов оператор амперсанда с унарным префиксом & означает" Взять объект Proc, который был передан в качестве аргумента, разверните его в блок и передайте в качестве аргумента блока. " Точнее, и это то, что включает «трюки», такие как Symbol#to_proc, это означает «Возьмите объект Proc, который был передан в качестве аргумента , или конвертируйте объект, используя to_proc, если он еще не является * 1030». *, разверните его в блок и передайте в качестве аргумента блока. "

В некотором смысле, они в точности противоположны друг другу.

В вашем первом примере Во втором случае у вас нет ни списка параметров, ни списка аргументов, так что ни & унарный префикс ampersand sigil, ни оператор & унарный префикс ampersand не являются синтаксически допустимыми.

Во втором случае второго примера, вы передаете результат :to_s.to_proc, который является Proc объектом, в качестве аргумента Range#map. Однако Range#map не имеет никаких параметров (кроме неявного параметра блока, который есть у каждого метода в Ruby), поэтому вы передаете один аргумент, где ни один не ожидается. Вы должны развернуть свой аргумент Proc в блок, подобный следующему:

(0..10).map(&(:to_s.to_proc))

, который можно сократить до

(0..10).map(&:to_s)

, поскольку оператор амперсанда с унарным префиксом & выполнит преобразование само по себе, если операнд уже не является Proc объектом.

2 голосов
/ 10 апреля 2020

& является внутренним оператором, который явно вызывает #to_proc для аргумента , а преобразует результат в блок .

Хотя блок несколько похоже на proc, это не совсем то же самое. Он не может существовать один, что означает, что нельзя создавать экземпляры блоков в дикой природе. И наоборот, нельзя передавать proc экземпляров методам, ожидающим блок. Они должны быть преобразованы в блоки заранее (с &.)

p = :to_s.to_proc     # fine, proc returned
p = &:to_s            # error, attempt to create block instance
(0..10).map &:to_s    # fine, the same as map { |e| e.to_s }
map(:to_s.to_proc)    # error, block is required, proc passed

# bonus
map(&:to_s.to_proc)   # fine, Proc.to_proc == self
map(&->(e){ e.to_s }) # fine, proc was converted to block
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...