2011-11-03 27 views
5

Chạy vào một số hành vi kỳ lạ và tự hỏi liệu có ai khác có thể xác nhận những gì tôi đang nhìn thấy hay không.Ruby attr_reader cho phép một biến đổi chuỗi biến đổi nếu sử dụng <<

Giả sử bạn tạo một lớp có biến thành viên và cho phép nó được đọc bằng attr_reader.

class TestClass 
    attr_reader :val 

    def initialize(value) 
    @val = value 
    end 
end 

Bây giờ khi tôi làm như sau, có vẻ như sửa đổi giá trị của @val, mặc dù tôi chỉ cấp quyền đọc.

test = TestClass.new('hello') 
puts test.val 
test.val << ' world' 
puts test.val 

này trả

hello 
hello world 

Đây mới chỉ là kết quả từ một số thử nghiệm tôi đã làm trong IRB vì vậy không chắc chắn nếu điều này luôn luôn là trường hợp

+0

'attr_reader' có nghĩa là bạn không thể đặt giá trị, nghĩa là không có phương thức' value = 'nào được xác định. Nó chắc chắn không có nghĩa là bạn không thể cal một phương thức trên đối tượng –

Trả lời

4

Bạn đang không thực sự bằng văn bản thuộc tính val. Bạn đang đọc nó và gọi một phương thức trên nó (phương thức '< <').

Nếu bạn muốn người truy cập ngăn chặn loại sửa đổi bạn mô tả, bạn có thể muốn triển khai phương thức trả về bản sao @val thay vì sử dụng attr_reader.

2

Chỉ cần một chút thay đổi trong ví dụ của bạn:

test = TestClass.new([]) 

Bây giờ bạn sẽ nhận được (thay thế puts với p để có được cái nhìn nội bộ):

[] 
['hello'] 

Đó là điều tương tự. Bạn 'đọc' val, và bây giờ bạn có thể làm điều gì đó với nó. Trong ví dụ của tôi, bạn thêm một cái gì đó vào mảng, trong ví dụ của bạn, bạn thêm một cái gì đó vào chuỗi của bạn.

Truy cập đọc lần đọc đối tượng (có thể được sửa đổi), quyền truy cập ghi thay đổi thuộc tính (thay thế nó).

Có lẽ bạn tìm kiếm freeze:

class TestClass 
    attr_reader :val 

    def initialize(value) 
    @val = value 
    @val.freeze 
    end 
end 

test = TestClass.new('hello') 
puts test.val 
test.val << ' world' 
puts test.val 

này kết thúc bằng:

__temp.rb:12:in `<main>': can't modify frozen string (RuntimeError) 
hello 
0

Trong khi này có vẻ bất ngờ, đây là hoàn toàn đúng. Hãy để tôi giải thích.

Phương thức macro lớp học xác định phương thức "getter" và "setter" cho các biến mẫu.

Không có phương thức "getter", bạn không có quyền truy cập vào các biến mẫu của đối tượng đơn giản chỉ vì bạn không ở trong ngữ cảnh của đối tượng đó. Phương pháp "setter" về cơ bản là thế này:

def variable=(value) 
    @variable = value 
end 

Kể từ khi điểm instance variable đến một đối tượng có thể thay đổi với một tập hợp các phương pháp riêng của mình, nếu bạn "lấy" nó và vận dụng nó, nó đứng vào lý do rằng những thay đổi đó sẽ lấy. Bạn không cần sử dụng phương thức setter ở trên để gọi variable.<<(value).

2

Chỉ định khác với sửa đổi và các biến khác với đối tượng.

test.val = "hello world" 

sẽ là một trường hợp phân đến @valdụ biến (mà sẽ không hoạt động), trong khi

test.val << " world" 

sẽ là một sửa đổi của đối tượng gọi bởi @val.

Why does the absence of the assignment operator permit me to modify a Ruby constant with no compiler warning? là một câu hỏi tương tự, nhưng nói về hằng số thay vì các biến mẫu.

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