2010-03-22 19 views
9

tôi đang tạo ra một ứng dụng đường ray và đã sử dụng mã này trong một trong những phương pháp của tôiTại sao tôi cần sử dụng .inject (0) thay vì .inject để thực hiện công việc này?

item_numbers.inject(0) {|sum, i| sum + i.amount} 

ITEM_NUMBERS đã là một mảng các đối tượng từ bảng ITEM_NUMBERS tôi. Phương thức .amount mà tôi áp dụng cho chúng tra cứu giá trị của một item_number trong một bảng riêng biệt và trả về nó như là một đối tượng BigDecimal. Rõ ràng là phương pháp tiêm sau đó thêm tất cả các đối tượng i.amount trả về và điều này hoạt động tốt.

Tôi chỉ tò mò là tại sao nó không hoạt động khi tôi đã viết bản Tuyên Bố này như

item_numbers.inject {|sum, i| sum + i.amount} 

Theo cuốn sách cuốc đáng tin cậy của tôi thì cũng nên tương đương. Có phải vì i.amount là một BigDecimal? Nếu vậy, tại sao nó bây giờ làm việc? Nếu không, thì tại sao nó không hoạt động.

Trả lời

14

những gì chúng ta có thể đọc trong API:.

Nếu bạn không xác định rõ ràng mộtGiá trị ban đầucho bản ghi nhớ, sau đó sử dụng phần tử thu thập đầu tiên được sử dụng làm giá trị ban đầu của bản ghi nhớ.

Vì vậy, item_numbers [0] sẽ được chỉ định làm giá trị ban đầu - nhưng không phải là số, nó là một đối tượng. Vì vậy, chúng tôi đã có một lỗi

phương pháp xác định `+'.

Vì vậy, chúng ta phải xác định giá trị ban đầu là 0

item_numbers.inject (0) {| Tóm lại, i | sum + i}

+0

Bạn có thể thực hiện một bài kiểm tra nhỏ (10..15) .inject do | sum, i | p tổng sum + i cuối nó sẽ trở lại: 10, 21, 33, 46, 60 => 75 Như bạn thấy _sum_ được mục đầu tiên từ mảng như giá trị ban đầu – fl00r

+0

Điều đó giải thích nó độc đáo. Cảm ơn. – brad

7

Đó là vì bạn đang truy cập i.amount thay vì chỉ đơn thuần là i. Trong phiên bản không hoạt động, bạn đang hoàn toàn làm item_numbers[0] + item_numbers[1].amount + ....

Một cách viết tắt sẽ là item_numbers.map(&:amount).inject(&:+), nhưng cách đó có thể dẫn đến hai lần lặp lại trong danh sách, nếu map không trả về điều tra viên.

Nếu điều đó đã không thuyết phục được bạn, hãy nhìn vào những gì được in ra nếu chúng ta định nghĩa một phương pháp amount trên Fixnum rằng in giá trị trước khi trở về nó:

irb(main):002:1> def amount 
irb(main):003:2>  puts "My amount is: #{self}" 
irb(main):004:2>  return self 
irb(main):005:2> end 
irb(main):006:1> end 
=> nil 
irb(main):007:0> [1,2,3].inject { |sum, i| sum + i.amount } 
My amount is: 2 
My amount is: 3 
=> 6 
irb(main):008:0> [1,2,3].inject(0) { |sum, i| sum + i.amount } 
My amount is: 1 
My amount is: 2 
My amount is: 3 
=> 6 
irb(main):009:0> 

Chúng ta có thể thấy rõ rằng amount không được gọi trên các yếu tố đầu tiên khi một giá trị khởi đầu không được thông qua một cách rõ ràng trong

+0

+1 cho ví dụ rõ ràng minh họa hành vi hoàn hảo – Jean

Các vấn đề liên quan