Статия за Procs от разбирането на Ruby Blocks, Procs и Lambdas

Добре, преглеждам Procs, lambdas и блокове чрез този връзка.

Въпрос относно този код:

class Array
  def iterate!
    self.each_with_index do |n, i|
      self[i] = yield(n)
    end
  end
end


array = [1, 2, 3, 4]

array.iterate! do |n|
  n ** 2
end

puts array.inspect

Концептуално разбирам почти всичко, с изключение на един ред, който е следният:

self[i] = yield(n)

Разбирам, че този self в този ред self.each_with_index do |n, i| означава, че е метод на клас, нали?

Но защо трябва да присвояваме параметрите в yield(n) на self[i]?

Моля, обяснете по супер основен начин, ако можете.

(с други думи, моля, бъдете любезни - каквито хора обикновено са в по-голямата си част тук - само малко допълнително нервен, че не разбирам това, което ме кара да се чувствам глупав)


person user273072545345    schedule 28.10.2014    source източник


Отговори (5)


Методът е iterate!, който е метод на екземпляр. self в self.each_with_index е приемникът на метода Enumerable#each_with_instance. Тъй като self е текущият екземпляр на Array ([1,2,3,4] във вашия пример), self. не е необходим; т.е. бихте могли (и imo, трябва) просто да напишете each_with_index do |n, i|.... С други думи, self е подразбиращият се получател, когато не е посочен изричен получател.

Относно линията:

self[i] = yield(n)

за вашия пример array = [1,2,3,4] вашият изброител е:

enum = [1,2,3,4].each_with_index
  #=> #<Enumerator: [1, 2, 3, 4]:each_with_index>

с елементи

enum.to_a
  #=> [[1, 0], [2, 1], [3, 2], [4, 3]]

Следователно първият елемент, предаден в блок от Array#each, е [1,0], който е присвоен на променливите на блока:

n = 1
i = 0

в резултат на което

self[0] = yield(1) => 1**2 => 1

и така нататък.

person Cary Swoveland    schedule 28.10.2014

Ще се опитам да обясня по супер основен начин.

Разбирам, че този self в този ред self.each_with_index do |n, i| означава, че е метод на клас, нали?

не Значението на self зависи от контекста. Ако self беше в класа, щеше да се отнася за класа. Но тук self е в метод на екземпляр, така че се отнася за екземпляра (така че each_with_index също е метод на екземпляр).

Но защо трябва да присвояваме параметрите в yield(n) до self[i]?

Целта на iterate! е да модифицира масива на място. Тъй като self се отнася до екземпляра, self[i] има достъп до елементите на масива, към който iterate! се извиква, като по този начин модифицира масива на място.

Освен това не съм сигурен какво имате предвид под „параметри“ тук. yield(n) предава n на блока, изпълнява блока и връща стойността.

person Max    schedule 28.10.2014

self[i] = yield(n) присвоява отново стойностите в масива към блока, който е посочен в

array.iterate! do |n|
  n ** 2
end

което основно означава, вземете стойността на масива и го повдигнете на квадрат, запазете тази стойност в елемента на масива. Така [1, 2, 3 , 4] става [1 ** 2, 2 ** 2, 3 ** 2, 4 ** 2] => [2, 4, 9, 16]

person SuckerForMayhem    schedule 28.10.2014

Аз се променя с (и всъщност е) текущия контекст или околния обект.

От

self.each_with_index do |n, i|
...

е маймунска корекция на класа Array и е в метод на инстанция iterate!, self се отнася до самата инстанция: в този случай масивът [1, 2, 3, 4].

Вероятно си мислите за това:

class some_class

  def self.a_class_method
  ...

който е дефиниран в контекста на клас. Така че self е самият клас (който също е обект), а не екземпляр на този клас.

Тъй като self е само масивът [1, 2, 3, 4]

self[i] = yield(n)

заменя всеки елемент от масива с резултати от изпратения блок.

person seph    schedule 28.10.2014

Тук итерирайте! е функция на екземпляр на клас Array и имате обект от масив. Когато го направите

array.iterate! do |n|
n ** 2
end

Предавате блок 'do |n| n**2 end' за повторение! функция. Във функцията можете да получите достъп до този блок, като използвате yield. Но както можете да видите, блокът очаква един параметър чрез |n| така че трябва да подадете един параметър и блоковият код ще върне неговия квадрат.

self[i] = yield(n)

self се използва в контекста на екземпляр на масив. Така че той променя стойностите на масива.

За повече информация, моля, проверете тази статия:

http://geekdirt.com/blog/blocks-lambda-and-procs-in-ruby/

person Shobhit_Geek    schedule 05.08.2015