2009-04-20 15 views
5

Giả sử bạn làm điều này trong Ruby:làm cho một đối tượng cư xử giống như một mảng chuyển nhượng song song trong ruby ​​

ar = [1, 2] 
x, y = ar 

Sau đó, x == 1 và y == 2. Có một phương pháp tôi có thể xác định trong tôi các lớp học riêng sẽ tạo ra cùng một hiệu ứng? ví dụ.

rb = AllYourCode.new 
x, y = rb 

Cho đến nay, tất cả những gì tôi có thể làm với một bài tập như thế này là làm x == rb và y = nil. Python có một tính năng như sau:

>>> class Foo: 
...  def __iter__(self): 
...    return iter([1,2]) 
... 
>>> x, y = Foo() 
>>> x 
1 
>>> y 
2 
+0

hoàn hảo, cảm ơn, đây chỉ là những gì tôi cần ở giây phút này. –

Trả lời

7

Đúng. Xác định #to_ary. Điều này sẽ cho phép đối tượng của bạn được coi là một mảng để gán.

irb> o = Object.new 
=> #<Object:0x3556ec> 
irb> def o.to_ary 
     [1, 2] 
    end 
=> nil 
irb> x, y = o 
=> [1,2] 
irb> x 
#=> 1 
irb> y 
#=> 2 

Sự khác biệt giữa #to_a#to_ary#to_a được sử dụng để cố gắng chuyển đổi một đối tượng nhất định để một mảng, trong khi #to_ary có sẵn nếu chúng ta có thể đối xử với những đối tượng nhất định như một mảng. Đó là một sự khác biệt tinh tế.

+0

Thực sự tinh tế; đây là sự phân biệt tương tự giữa == và eql? mà tôi thực sự không thích. Tại sao nên có to_a AND to_ary ??? – allyourcode

+1

to_ary là dành cho các đối tượng có hiệu quả mảng. Nếu một cái gì đó thực sự cần phải sử dụng một mảng có thể sử dụng đối tượng của bạn thay vì một mảng và đối tượng của bạn có nghĩa là một mảng, sau đó nó nên thực hiện to_ary. to_a dành cho những thứ có thể chuyển đổi thành mảng, ví dụ: đối tượng với (chấm dứt) mỗi phương thức có một thực hiện rõ ràng của to_a. Ví dụ. một tập tin có thể có một phương thức to_a, nhưng bạn không thể xử lý nó như là một mảng, và nó không mô hình hóa một mảng để nó không có phương thức to_ary. –

1

Bạn không thể xác định lại bài tập vì đó là toán tử thay vì phương pháp. Nhưng nếu lớp AllYourCode của bạn được kế thừa từ Array, ví dụ của bạn sẽ hoạt động.

Khi Ruby gặp một nhiệm vụ, nó nhìn vào phía bên phải và nếu có nhiều hơn một giá trị, nó sẽ thu thập chúng thành một mảng. Sau đó, nó nhìn ở phía bên tay trái. Nếu có một lvalue ở đó, nó được gán mảng.

def foo 
    return "a", "b", "c" # three rvalues 
end 

x = foo # => x == ["a", "b", "c"] 

Nếu có nhiều hơn một giá trị (cụ thể hơn nếu thấy dấu phẩy), nó sẽ gán giá trị liên tục và loại bỏ các giá trị bổ sung.

x, y, z = foo # => x == "a", y == "b", z == "c" 
x, y = foo # => x == "a", y == "b" 
x, = foo  # => x == "a" 

Bạn có thể thực hiện gán song song nếu mảng cũng được trả lại như bạn đã khám phá.

def bar 
    ["a", "b", "c"] 
end 

x = bar  # => x == ["a", "b", "c"] 
x, y, z = bar # => x == "a", y == "b", z == "c" 
x, y = bar # => x == "a", y == "b" 
x, = bar  # => x == "a" 

Vì vậy, trong ví dụ của bạn, nếu rb là Mảng hoặc kế thừa từ mảng, x và y sẽ được gán 2 giá trị đầu tiên.

+0

Tôi nghĩ bạn có ý định đặt dấu ngoặc xung quanh "a", "b", "c" trong ví dụ đầu tiên của bạn. Khi tôi thử nó, tôi nhận được một lỗi cú pháp. – allyourcode

+0

Thực ra tôi đã quên "trả lại". Đã sửa lỗi. –

2

Hầu như:

class AllYourCode 
    def to_a 
    [1,2] 
    end 
end 

rb = AllYourCode.new 
x, y = *rb 
p x 
p y 

Splat sẽ cố gắng để gọi to_ary, và sau đó cố gắng gọi to_a. Tôi không chắc chắn lý do tại sao bạn muốn làm điều này mặc dù, điều này thực sự là một tính năng cú pháp xảy ra để sử dụng Array trong việc thực hiện của nó, chứ không phải là một tính năng của Array.

Nói cách khác, trường hợp sử dụng cho nhiều nhiệm vụ là những thứ như:

# swap 
x, y = y, x 

# multiple return values 
quot, rem = a.divmod(b) 

# etc. 
name, age = "Person", 100 

Nói cách khác, phần lớn thời gian các đối tượng được giao từ (các Array) là thậm chí không rõ ràng.

+2

Điều này có phần hữu ích, nhưng tôi ghét nó khi tôi đặt câu hỏi và mọi người tin rằng tôi không có lý do chính đáng để làm những gì tôi đang cố gắng làm. Nếu bạn nghĩ rằng đây là một ý tưởng tồi, hãy giải thích tại sao !! Tôi đánh giá cao các ví dụ của bạn, nhưng việc hiển thị các cách sử dụng điển hình không giải thích điều gì tôi đang cố gắng làm:/ – allyourcode

+0

Tôi không nói bạn không có lý do chính đáng, tôi chỉ nói rằng tôi không biết lý do là. Tôi không thể nói một ý kiến ​​về việc nó tốt hay không cho đến khi tôi biết nó là gì. Tôi chắc chắn không thể nói rằng không bao giờ có một hoàn cảnh mà bạn muốn làm điều này, nhưng nếu bạn muốn thưởng thức sự tò mò của tôi, tôi sẽ đánh giá cao nó. –

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