2011-01-27 28 views
22

Gần đây tôi phát hiện ra rằng tap có thể được sử dụng để "khoan nhượng" gán giá trị cho các biến mới; Ví dụ, để tạo và làm đầy một mảng, như thế này:Phương pháp Ruby 'tap' - bên trong gán

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

Mã này sẽ đẩy 5 vào array nếu something là truthy; nếu không, array sẽ vẫn trống.

Nhưng tôi không hiểu tại sao sau khi thực hiện mã này:

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

array vẫn trống. Ai giúp tôi với?

Trả lời

38

Trong trường hợp đầu tiên, arrayary trỏ đến cùng một đối tượng. Sau đó bạn biến đổi đối tượng đó bằng cách sử dụng phương thức <<. Đối tượng mà cả hai arrayary điểm đến bây giờ đã được thay đổi.

Trong trường hợp thứ hai arrayary lại cả hai điểm vào cùng một mảng. Bây giờ bạn gán lại biến số ary, để ary hiện trỏ đến một mảng mới. Chỉ định lại ary tuy nhiên không ảnh hưởng đến array. Trong ruby ​​gán lại một biến không bao giờ ảnh hưởng đến các biến khác, ngay cả khi chúng trỏ đến cùng một đối tượng trước khi gán lại.

Nói cách khác array vẫn còn trống vì lý do tương tự mà x sẽ không được 42 trong ví dụ sau:

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

Edit: Để thêm một mảng khác tại chỗ bạn có thể sử dụng concat cũng nên nhanh hơn sử dụng +=.

+5

THÊM: 'a + = b' hoạt động như' a = a + b' - ở đây việc tạo một đối tượng mới rõ ràng hơn. – Nakilon

+1

@Nakilon: Do OP nói rõ ràng về nhiệm vụ, tôi cho rằng phần đó rõ ràng với anh ấy. – sepp2k

+0

ok, tôi nghĩ rằng tôi hiểu; nó không hoạt động beacuse của hoạt động gán. Để có được hiệu quả mà tôi muốn tôi nên làm array = [].tap { |ary| [5].each{ |v| ary << 5 } } --- Làm cách nào để bạn có thể thêm định dạng vào nhận xét của mình ?? – mdesantis

20

tôi muốn mở rộng về vấn đề này một chút:

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

Điều này không (giả sử something là đúng-ish):

  1. gán array-[], một mảng trống.

    array.object_id = 2152428060 
    
  2. đi [] vào khối như ary. aryarray đang trỏ đến cùng một đối tượng mảng.

    array.object_id = 2152428060 
    ary.object_id = 2152428060 
    
  3. ary << 5 < < là một phương pháp mutative, có nghĩa là nó sẽ thay đổi đối tượng tiếp nhận. Nó tương tự như thành ngữ của việc thêm ! vào một cuộc gọi phương thức, có nghĩa là "sửa đổi điều này tại chỗ!", Như trong .map.map! (mặc dù bang không giữ bất kỳ ý nghĩa nội tại nào trong tên phương thức).ary đã 5 chèn, vì vậy ary = array = [5]

    array.object_id = 2152428060 
    ary.object_id = 2152428060 
    

Chúng tôi kết thúc với array là bằng [5]

Trong ví dụ thứ hai:

array = [].tap{ |ary| ary += [5] if something }  
  1. cùng
  2. cùng
  3. ary += 5+= là viết tắt của ary = ary + 5, vì vậy nó là thay đổi đầu tiên (+) và sau đó chuyển nhượng (=), theo thứ tự đó. Nó cho sự xuất hiện của sửa đổi một đối tượng tại chỗ, nhưng nó thực sự không. Nó tạo ra một đối tượng hoàn toàn mới.

    array.object_id = 2152428060 
    ary.object_id = 2152322420 
    

Vì vậy, chúng tôi kết thúc với array như đối tượng gốc, một mảng trống với object_id=2152428060, và ary, một mảng với một mục chứa 5 với object_id = 2152322420. Không có gì xảy ra với ary sau này. Nó không được giải quyết với nhiệm vụ ban đầu của array, điều đó đã xảy ra. Nhấn thực hiện khối sau khi array đã được gán.

+1

đây là câu trả lời và giải thích tuyệt vời nhất. – tamouse

+1

Giải thích tuyệt vời - được thực hiện. – Jurgen

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