Рубиновый метод «tap» - внутреннее назначение - PullRequest
24 голосов
/ 27 января 2011

Недавно я обнаружил, что tap можно использовать для «сухого» назначения значений новым переменным;например, для создания и заполнения массива, например:

array = [].tap { |ary| ary << 5 if something }

Этот код будет толкать 5 в array, если something верно;иначе, array останется пустым.

Но я не понимаю, почему после выполнения этого кода:

array = [].tap { |ary| ary += [5] if something }

array остается пустымКто-нибудь может мне помочь?

Ответы [ 2 ]

40 голосов
/ 27 января 2011

В первом случае array и ary указывают на один и тот же объект. Затем вы изменяете этот объект, используя метод <<. Объект, на который указывают array и ary, теперь изменен.

Во втором случае array и ary снова оба указывают на один и тот же массив. Теперь вы переназначаете переменную ary, так что ary теперь указывает на новый массив. Переназначение ary однако не влияет на array. В ruby ​​переназначение переменной никогда не влияет на другие переменные, даже если они указывали на один и тот же объект до переназначения.

Другими словами, array по-прежнему пуст по той же причине, что x не будет 42 в следующем примере:

x = 23
y = x
y = 42 # Changes y, but not x

Редактировать: Чтобы добавить один массив к другому на месте, вы можете использовать метод concat, который также должен быть быстрее, чем +=.

21 голосов
/ 24 июля 2013

Я хочу немного подробнее остановиться на этом:

array = [].tap { |ary| ary << 5 if something }

Что это делает (при условии, что something соответствует действительности):

  1. назначает array до [], пустой массив.

    array.object_id = 2152428060
    
  2. передает [] в блок как ary.ary и array указывают на один и тот же объект массива.

    array.object_id = 2152428060
    ary.object_id = 2152428060
    
  3. ary << 5 << - это мутативный метод, означающий, что он изменит принимающий объект.Это похоже на идиому добавления <code>! к вызову метода, что означает «изменить это на месте!», Как в .map против .map! (хотя взрыв не имеет никакого собственного внутреннего значения в методеназвание).ary имеет 5 вставленных, поэтому ary = array = [5]

    array.object_id = 2152428060
    ary.object_id = 2152428060
    

Мы заканчиваем с array равным [5]

Во втором примере:

array = [].tap{ |ary| ary += [5] if something }    
  1. то же самое
  2. то же самое
  3. ary += 5 += - это сокращение от ary = ary + 5, поэтомуэто первая модификация (+), а затем присвоение (=), в этом порядке.Это создает видимость изменения объекта на месте, но на самом деле это не так.Он создает совершенно новый объект.

    array.object_id = 2152428060
    ary.object_id = 2152322420
    

Итак, мы заканчиваем array в качестве исходного объекта, пустым массивом с object_id=2152428060 и ary, массивом содин предмет, содержащий 5 с object_id = 2152322420.Ничего не происходит с ary после этого.Это не связано с первоначальным назначением array, которое уже произошло.Тап выполняет блок после назначения array.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...