這是密集的代碼,沒問題。所以,正如你所說的before
和after
是作爲參數遞交到方法中的散列(類似?)對象。調用before.diff(after)
會返回另一個散列,然後立即調用.keys
。這將返回diff
返回的散列中的所有密鑰。密鑰以數組形式返回,然後立即排序。
然後我們得到最複雜/密集的位。在該排序的鍵數組上使用inject
,該方法建立一個數組(在inject
塊內部稱爲diffs
),該數組將作爲inject
方法的返回值。這個數組是由差異記錄組成的。每條記錄都是散列 - 通過從before.diff(after)
返回值的排序數組中獲取一個鍵來構建。這些散列存儲正在被擴散的屬性,它在前面的散列中看起來像什麼,以及它在後面的散列中看起來像什麼。
所以,簡而言之,該方法獲得了兩個哈希值之間的一堆差異,並將它們收集在一個哈希數組中。該散列數組是該方法的最終返回值。
注意:inject
可以,並且往往比這更簡單得多。通常它只是簡單地將一組值減少到一個結果,一次又一次地應用一個操作並將結果存儲在一個累加器中。你可能知道inject
爲其他語言的reduce
; reduce
是Ruby中的inject
的別名。這裏有一個簡單得多的例子:inject
:
[1,2,3,4].inject(0) do |sum, number|
sum + number
end
# => 10
0是累加器 - 初始值。在配對|sum, number|
中,sum
將是累加器,並且number
將依次爲數組中的每個數字。 inject
所做的是將1加1,將結果存儲在sum
中進行下一輪,將2加到sum
,再將結果存儲在sum
中等等。累加器sum
的單個最終值將作爲返回值。這裏10.在你的例子中增加的複雜性是,累加器與塊內的值不同。這是不常見的,但不壞或單一。 (編輯:安德魯·馬歇爾使好點,也許這是不好見他對原來的問題發表意見,並@tokland指出,這裏的inject
只是一個非常過分複雜的地圖替代它是壞。 。)請參閱我鏈接到您的問題的評論中的文章,以獲取更多inject
的示例。
編輯:@tokland在一些評論中指出,代碼似乎只需要一個簡單的map
。這會讀起來容易得多。
def differences(before, after)
before.diff(after).keys.sort.map do |k|
{ :attribute => k, :before => before[k], :after => after[k] }
end
end
我太專注於解釋代碼在做什麼。我什至想不到如何簡化它。
'inject'的使用有些複雜。對於一個很好的博客文章,以'inject'爲基礎開始,並建立起來,像你在這裏的例子,看看這個:http://blog.jayfields.com/2008/03/ruby-inject.html。 – Telemachus
這裏'inject'的使用在語義上可能是錯誤的,Ruby 1.9增加了['each_with_object'](http://ruby-doc.org/core-1.9.3/Enumerable.html#method-i-each_with_object)這個例子更有意義。 –
@AndrewMarshall:不需要'inject'和'each_with_object',這應該是一個'map',一個簡單而簡單的'map'。 – tokland