Спасибо @sawa теперь больше ясности о вкладке и yield_self ...

2.5.0-rc1 был выпущен и представляет новыйKernel#yield_self метод.

В чем разница междуyield_self, yield(self) и существующийObject#tap метод?

 Sergio Tulentsev19 дек. 2017 г., 16:56
Этот вопрос, вероятно, получит некоторый трафик, так как все больше и больше разработчиков обдумывают это. +1 за полезность, -1,5 за презентацию. Пожалуйста, потратьте немного времени и сделайте это хорошего качества. (форматирование, грамматика, пунктуация, некоторая дополнительная информация и т. д.). Это может быть примерным справочным вопросом.

Ответы на вопрос(3)

Решение Вопроса

tap а такжеyield_self находится в том, что возвращается каждым из двух методов.

Object#tap уступает себя блокуа затем возвращает себя. Kernel#yield_self уступает себя блоку, а затемвозвращает результат блока.

Вот несколько примеров, где каждый может быть полезен:

нажмите

Замена необходимости вresult строка в конце метода:

def my_method
  result = get_some_result
  call_some_method_with result
  result
end

можно записать как:

def my_method
  get_some_result.tap do |result|
    call_some_method_with result
  end
end

Другим примером является инициализация некоторого объекта, который выполняет несколько шагов:

some_object = SomeClass.new.tap do |obj|
  obj.field1 = some_value
  obj.field2 = other_value
end   
yield_self и yield (self)

Если используется внутри одного из ваших собственных методовyield_self будет иметь такой же эффект, какyield(self), Однако, имея его в качестве отдельного метода, это способствует объединению методов в качестве альтернативы вызовам вложенных функций.

Этот пост в блоге Михал Ломницкий имеет несколько полезных примеров. например этот код:

CSV.parse(File.read(File.expand_path("data.csv"), __dir__))
   .map { |row| row[1].to_i }
   .sum

можно переписать как:

"data.csv"
  .yield_self { |name| File.expand_path(name, __dir__) }
  .yield_self { |path| File.read(path) }
  .yield_self { |body| CSV.parse(body) }
  .map        { |row|  row[1].to_i }
  .sum

Это может помочь с ясностью, когда вложенные вызовы используются для ряда преобразований в некоторых данных. Подобные функции существуют в других языках программирования.Трубный оператор в Эликсире на это хорошо взглянуть,

 Vivek Singh20 дек. 2017 г., 09:11
Спасибо за ваше объяснение @mikej

Ruby 2.5 добавил yield_self.

Быстрое обновление:yield_self будет иметь псевдонимthen в новых версиях Ruby, следующие запросы от сообщества, чтобы это было более читабельным.

Это очень хорошее, краткое чтение, приведенное ниже для потомков. Вся благодарность первоначальному автору, Виджей Кумар Агравал:

В Ruby 2.5 добавлен новый метод yield_self. Он возвращает получателя данному блоку и возвращает вывод последнего оператора в блоке.

irb> "Hello".yield_self { |str| str + " World" }
  => "Hello World"

Чем он отличается от try в Rails?

Без аргумента метода try ведет себя аналогично yield_self. Он будет уступать данному блоку, если только получатель не равен nil и не возвращает вывод последнего оператора в блоке

irb> "Hello".try { |str| str + " World" }
  => "Hello World"

Обратите внимание на пару отличий: попробуйте не часть Ruby, а Rails. Также основная цель try - защита от нуля, следовательно, он не выполняет блок, если получатель равен нулю.

irb> nil.yield_self { |obj| "Hello World" }
  => "Hello World"

irb> nil.try { |obj| "Hello World" }
  => nil

Как насчет крана?

тап также похож на yield_self. Это часть самого Ruby. Единственное отличие - это возвращаемое значение. tap возвращает самого получателя, а yield_self возвращает выходные данные блока.

irb> "Hello".yield_self { |str| str + " World" }
  => "Hello World"

irb> "Hello".tap { |str| str + " World" }
  => "Hello"

В целом yield_self улучшает читабельность кода, способствуя связыванию вызовов вложенных функций. Вот пример обоих стилей.

irb> add_greeting = -> (str) { "HELLO " + str }
irb> to_upper = -> (str) { str.upcase }

# with new `yield_self`
irb> "world".yield_self(&to_upper)
            .yield_self(&add_greeting)
  => "HELLO WORLD"

# nested function calls
irb> add_greeting.call(to_upper.call("world"))
  => "HELLO WORLD"

yield_self является частью ядра и, следовательно, он доступен для всех объектов.

Пожалуйста, не принимайте это как ответ, так как это не моя собственная работа (и я рад удалить, если у кого-то есть какие-либо возражения), - но я нашел это очень хорошее чтение и подумал, что это может помочь другим в какой-то момент.

 Cary Swoveland19 дек. 2017 г., 18:49
Эта ссылка полезна, но ссылка в комментарии будет достаточной и уместной.
 Sergio Tulentsev20 дек. 2017 г., 09:26
Я бы хотел, чтобы это осталось. @SRack: тыможет превратить этот ответ в вики сообществатак, чтобы вы не извлекли выгоду из голосов на контент, который вы не производили :)
 SRack19 дек. 2017 г., 18:52
Приветствия @CarySwoveland, я действительно думал, что, хотя количество раз, когда я перешел по неработающей ссылке, я думал, что было бы удобно иметь возможность ссылаться на это напрямую. Как сказано, с удовольствием удалим, если консенсус будет за это.
 SRack20 дек. 2017 г., 11:01
Хорошая идея @SergioTulentsev - не знал об этом варианте. Я переключил это сейчас. Спасибо за совет!

параллелизм междуeach противmap а такжеtap противyield_self.

Есть много вопросов, задающих разницу междуeach а такжеmap для перечисления. Первый используется для выполнения чего-либо с побочным эффектом или чего-то деструктивного, а затем для возврата получателя, что удобно для методов цепочки. Последний возвращает оцененное значение вместо каждого элемента в приемнике.

tap противyield_self просто так; Разница в том, что они сделаны для одного объекта-получателя, а не для элементов в перечисляемом получателе. Таким образом, их вариант использования будет соответствовать тому, что я написал выше. Первый используется для выполнения чего-либо с побочным эффектом или чего-то деструктивного, а затем для возврата получателя, что удобно для методов цепочки. Последний возвращает оцененное значение вместо получателя.

 Vivek Singh20 дек. 2017 г., 09:45
Спасибо @sawa теперь больше ясности о вкладке и yield_self ...

Ваш ответ на вопрос