2010-01-18 24 views
22

Công cụ thể loại lớp ruby ​​đang khiến tôi đau đầu. Tôi hiểu được điều này ...Biến lớp Ruby

class Foo 
    @var = 'bar' 
end 

... rằng @var là một biến trên cá thể của lớp được tạo.

Nhưng làm cách nào để tạo biến lớp có thể ghi đè lên lớp phụ?

Dưới đây là một ví dụ về những gì tôi sẽ làm gì trong Python:

class Fish: 
var = 'fish' 
def v(self): 
    return self.var 

class Trout(Fish): 
    var = 'trout' 

class Salmon(Fish): 
    var = 'salmon' 

print Trout().v() 
print Salmon().v() 

Những kết quả đầu ra:

trout 
salmon 

Làm thế nào để làm điều tương tự trong ruby?

+1

shouldn' đó là một @@ var trong khối mã đầu tiên? – Jean

+0

Tôi đang đọc "Rubyist Grounded" (http://manning.com/black2/) của David Black. Anh ấy làm một công việc tuyệt vời giải thích tất cả các sắc thái trong khu vực này –

+1

Jean: Không. Nếu tôi sử dụng '@@ var' thì các lớp con sẽ ghi đè lên các lớp cha. Xem liên kết của hobodave. Cụ thể như thế nào '2' là overriden trong ví dụ. –

Trả lời

8

@var đề cập ở trên được gọi là lớp dụ biến, đó là khác biệt so với biến dụ ... đọc câu trả lời here để xem diff.

Dù sao đây là mã Ruby tương đương:

class Fish 
    def initialize 
    @var = 'fish' 
    end 

    def v 
    @var 
    end 
end 

class Trout < Fish 
    def initialize 
    @var = 'trout' 
    end 
end 

class Salmon < Fish 
    def initialize 
    @var = 'salmon' 
    end 
end 

puts Trout.new.v 
puts Salmon.new.v 
+0

Nó không thực sự, bởi vì bạn phải ghi đè lên khởi tạo mỗi khi bạn phân lớp. Mà không phải là rất có thể sử dụng. Nó có thể đã được tốt hơn trong ví dụ của tôi để bao gồm một số mã trong khởi tạo. –

21

Để phản @ câu trả lời khelll, điều này sử dụng các biến dụ trên các đối tượng Class:

class Fish 
    # an instance variable of this Class object 
    @var = 'fish' 

    # the "getter" 
    def self.v 
    @var 
    end 

    # the "setter" 
    def self.v=(a_fish) 
    @var = a_fish 
    end 
end 

class Trout < Fish 
    self.v = 'trout' 
end 

class Salmon < Fish 
    self.v = 'salmon' 
end 

p Trout.v # => "trout" 
p Salmon.v # => "salmon" 

Edit: để cung cấp cho các trường hợp Read- truy cập vào biến cá thể của lớp học:

class Fish 
    def type_of_fish 
    self.class.v 
    end 
end 

p Trout.new.type_of_fish # => "trout" 
p Salmon.new.type_of_fish # => "salmon" 
+0

Không, không hoàn toàn. Bạn không làm một Trout.new hoặc Salmon.new ở cuối. Bạn đang sử dụng chính lớp đó. Tôi muốn các * dụ * để có được các biến lớp. –

+0

@ Bác sĩ - còn bây giờ thì sao? –

+0

Yup. Tôi nghĩ rằng nó bây giờ là equiv chức năng. với câu trả lời tôi đưa ra. Bạn chỉ cần viết các accessors bằng tay. –

2

Đó là một sai lầm phổ biến được thực hiện bởi các lập trình viên Java đến với Ruby là tốt, và một trong những bước nhảy khái niệm lớn tôi đã có để có được đầu của tôi xung quanh. Lúc đầu nó có vẻ kỳ quặc, nhưng nó thực sự là một trong những khía cạnh thú vị của Ruby - tất cả các mã đều có thể thực thi được, bao gồm các định nghĩa lớp.

Vì vậy, các biến mẫu phải được khai báo bên trong các phương thức. Nó phải liên quan đến cách thức 'tự' được đánh giá. 'self' là đối tượng hiện tại. Thông dịch viên sẽ tra cứu các cuộc gọi phương pháp và tài liệu tham khảo biến đầu tiên trong 'tự':

class Fish 
    @var = "foo" # here 'self' == Fish, the constant which contains the class object 
    def foo 
     # do foo 
    end 
end 

fish = Fish.new 
fish.foo # here 'self' == fish, an instance of Fish 

Trong một định nghĩa lớp, 'tự' được đặt là đối tượng lớp được xác định, vì vậy bất kỳ tài liệu tham khảo trong một định nghĩa lớp sẽ tham khảo đối tượng lớp đó, trong trường hợp này là Cá.

Khi phương thức được gọi trên cá thể cá, tuy nhiên, bản thân được đặt làm người nhận cuộc gọi, cá thể cá cụ thể. Vì vậy, bên ngoài định nghĩa phương thức, tự là đối tượng lớp. Bên trong một phương thức, bản thân nó là thể hiện của người nhận. Đây là lý do tại sao @var bên ngoài một định nghĩa phương thức giống như một biến tĩnh trong Java, và @var bên trong một định nghĩa phương thức là một biến cá thể.

+0

Lỗi: 'fish.foo' phải là' fish.var' –

+0

Thực ra, không. Tôi không định nghĩa 'foo' nhưng quan điểm là thông dịch viên Ruby sẽ thấy 'cá' là người nhận cuộc gọi và đặt 'self' thành 'fish' để giải quyết tham chiếu. Tôi đã thêm phương pháp foo cho rõ ràng mặc dù. Gọi 'fish.var' sẽ ném một NoMethodError. –

+0

Ah. Lỗi của tôi. Cảm ơn vì đã giải thích nó. –

4

Dưới đây là phiên bản tôi đã kết thúc tìm ra sử dụng liên kết hobodave của:

class Fish 
    class << self 
    attr_accessor :var 
    end 

    @var = 'fish' 
    def v 
    self.class.var 
    end 
end 

class Trout < Fish 
    @var = 'trout' 
end 

class Salmon < Fish 
    @var = 'salmon' 
end 

puts (Trout.new).v # => trout 
puts (Salmon.new).v # => salmon 

ý rằng subclassing chỉ cần thêm một @var - không cần phải ghi đè khởi tạo.

1

Có một vấn đề một: bạn có thể ghi đè @var:
Salmon.var = 'cá mập' sẽ ghi đè @var, vì vậy
puts (Salmon.new) v # => cá mập

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