2012-04-30 18 views
42

Những gì tôi muốn là:Trong Ruby, mối quan hệ giữa 'mới' và 'khởi tạo' là gì? Làm thế nào để trả về nil khi khởi tạo?

obj = Foo.new(0) # => nil or false 

này không hoạt động:

class Foo 
    def initialize(val) 
    return nil if val == 0 
    end 
end 

Tôi biết trong C/C++/Java/C#, chúng tôi không thể trả về một giá trị trong một constructor.

Nhưng tôi tự hỏi liệu điều đó có thể xảy ra trong Ruby hay không.

+12

Nếu đây là một kiểm tra sự lành mạnh, điều thân thiện hơn là làm tăng ngoại lệ giải thích * tại sao * bạn không tiếp tục khởi tạo. Trả lại nil chỉ là sẽ tạo ra sự nhầm lẫn (nghiêm trọng). Không ai có thể mong đợi một đối tượng mới được khởi tạo là không;) – d11wtq

+0

Không có hàm tạo nào trong 'C'. – YoTengoUnLCD

+3

Ngoại lệ đáng chú ý đối với câu lệnh @ d11wtq sẽ là 'NilClass.new()'. –

Trả lời

5

Bạn có một cái gì đó như thế này:

class Foo 

    def self.init(val) 
    new(val) unless val == 0 
    end 

    def initialize(val) 
    #... 
    end 
end 

Ví dụ về sử dụng:

obj = Foo.init(0) 
=> nil 
obj = Foo.init(5) 
=> #<Foo:0x00000002970a98> 
+0

Trong ví dụ của bạn thực hiện cuộc gọi này cũng mới? – holaSenor

+0

Nếu bạn có nghĩa là ví dụ khi chúng ta gọi 'init' bằng 0, thì không,' new' sẽ không được gọi. – Flexoid

42

Có sự khác biệt quan trọng giữa hai phương pháp.

new là một phương pháp lớp, thường tạo ra một thể hiện của lớp (điều này giải quyết những thứ phức tạp như cấp phát bộ nhớ mà Ruby bảo vệ bạn để bạn không phải quá bẩn).

Sau đó, initialize, một phương thức dụ, yêu cầu đối tượng đặt trạng thái nội bộ của nó theo các thông số được yêu cầu.

Một trong hai tùy chọn này có thể bị ghi đè tùy thuộc vào những gì bạn muốn. Ví dụ: Foo.new thực sự có thể tạo và trả lại phiên bản FooSubclass nếu cần đủ thông minh để thực hiện điều đó.

Tuy nhiên, thường tốt hơn là ủy quyền các trường hợp sử dụng như thế này cho các phương thức lớp khác rõ ràng hơn về những gì họ làm, ví dụ: Foo.relating_to(bar). Phá vỡ những mong đợi của người khác về những phương pháp như new nên làm sẽ gây nhầm lẫn cho mọi người nhiều hơn là nó sẽ giúp họ trong thời gian dài.

Ví dụ, xem xét việc triển khai Singleton, một mô-đun chỉ cho phép một phiên bản của một lớp cụ thể tồn tại. Nó làm cho phương thức new là riêng tư và hiển thị phương thức instance trả về phiên bản hiện tại của đối tượng hoặc gọi new nếu chưa được tạo.

71

Trong Ruby, mối quan hệ giữa 'new' và 'initialize' là gì?

new thường gọi initialize. Việc triển khai mặc định là new là một cái gì đó như:

class Class 
    def new(*args, &block) 
    obj = allocate 

    obj.initialize(*args, &block) 
    # actually, this is obj.send(:initialize, …) because initialize is private 

    obj 
    end 
end 

Nhưng bạn có thể, tất nhiên, ghi đè lên để làm bất cứ điều gì bạn muốn.

Làm cách nào để trả về số không khi khởi tạo?

Những gì tôi muốn là:

obj = Foo.new(0) # => nil or false 

này không hoạt động:

class Foo 
    def initialize(val) 
    return nil if val == 0 
    end 
end 

Tôi biết trong C/C++/Java/C#, chúng tôi không thể trả về một giá trị trong một constructor.

Nhưng tôi tự hỏi liệu điều đó có thể xảy ra trong Ruby hay không.

Không có điều nào như một nhà xây dựng trong Ruby. Các nhà xây dựng không cần thiết trong một ngôn ngữ được thiết kế tốt. Trong Ruby, chỉ có các phương thức và các phương thức của khóa học có thể trả về các giá trị.

Vấn đề bạn đang thấy đơn giản là bạn muốn thay đổi giá trị trả về của một phương pháp nhưng bạn đang ghi đè một phương pháp khác. Tất nhiên không hoạt động. Nếu bạn muốn thay đổi giá trị trả lại của phương thức bar, bạn nên ghi đè bar, không phải một số phương pháp khác.

Nếu bạn muốn thay đổi hành vi của Foo::new, sau đó bạn nên thay đổi Foo::new:

class Foo 
    def self.new(val) 
    return nil if val.zero? 
    super 
    end 
end 

Lưu ý, tuy nhiên, đây là một ý tưởng thực sự xấu, vì nó vi phạm hợp đồng của new, mà là trả về một thể hiện đầy đủ, được khởi tạo đầy đủ của lớp.

+0

Có phải 'self.new' đúng không? Nó không phải là 'Foo.new'? – Kashyap

+2

'self' * là *' Foo' ở đó. Hãy thử 'class Foo; p tự kết thúC# => Foo' –

4

Muốn làm

class Foo 
    def initialize(val) 
    return nil if val == 0 
    end 
end 

sẽ làm cho mã không phù hợp.

Nếu bạn có

class Foo 
    def initialize(val) 
    return nil if val == 0 
    @val = val 
    @bar = 42 
    end 
end 

những gì bạn muốn để có được trở lại nếu bạn đã làm Foo.new(1)? Bạn có muốn 42 (giá trị trả lại cho Foo#initialize) hoặc đối tượng foo không? Nếu bạn muốn một đối tượng foo cho Foo.new(1), thì tại sao bạn mong đợi return nil để thực hiện trả lại Foo.new(0) không?

-1

Nó được giải quyết bằng cách đơn giản là tạo ra một biến đối tượng như thế này:

class Foo 
    def initialize(val) 
     @val = val 
     return nil if @val == 0 
    end 
end 
obj = Foo.new(0) 

Output:- 
=>#<Foo:0x1243b8 @val=0> 

Sản lượng dao động trong máy tính khác nhau.

2

Các lớp trong Ruby là các đối tượng hạng nhất - mỗi lớp là một thể hiện của lớp Class. Khi một lớp mới được định nghĩa (thường sử dụng tên lớp ... kết thúc), một đối tượng kiểu lớp được tạo ra và gán cho một hằng số (Tên. Trong trường hợp này). Khi Name.new được gọi để tạo một đối tượng mới, phương thức lớp mới trong Class được chạy theo mặc định, mà lần lượt gọi cấp phát để cấp phát bộ nhớ cho đối tượng, trước khi cuối cùng gọi phương thức khởi tạo của đối tượng mới. Việc xây dựng và khởi tạo các giai đoạn của một đối tượng là riêng biệt và cả hai có thể được over-ridden. Việc xây dựng được thực hiện thông qua phương thức lớp mới, khởi tạo được thực hiện thông qua phương thức khởi tạo cá thể. khởi tạo không phải là một hàm tạo!