2011-01-13 12 views
8

Có sự đồng thuận về cách tránh việc ghi nhớ gây ra lỗi do trạng thái có thể thay đổi không?Làm cách nào để tránh ghi nhớ gây ra lỗi trong Ruby?

Trong ví dụ này, kết quả được lưu trong bộ nhớ cache bị biến đổi trạng thái, và do đó cho kết quả sai lần thứ hai được gọi.

class Greeter 

    def initialize 
    @greeting_cache = {} 
    end 

    def expensive_greeting_calculation(formality) 
    case formality 
     when :casual then "Hi" 
     when :formal then "Hello" 
    end 
    end 

    def greeting(formality) 
    unless @greeting_cache.has_key?(formality) 
     @greeting_cache[formality] = expensive_greeting_calculation(formality) 
    end 
    @greeting_cache[formality] 
    end 

end 

def memoization_mutator 
    greeter = Greeter.new 
    first_person = "Bob" 
    # Mildly contrived in this case, 
    # but you could encounter this in more complex scenarios 
    puts(greeter.greeting(:casual) << " " << first_person) # => Hi Bob 
    second_person = "Sue" 
    puts(greeter.greeting(:casual) << " " << second_person) # => Hi Bob Sue 
end 

memoization_mutator 

phương pháp tiếp cận tôi có thể nhìn thấy để tránh điều này là:

  1. greeting có thể trở lại một dup hoặc clone của @greeting_cache[formality]
  2. greeting thể freeze kết quả của @greeting_cache[formality]. Điều đó sẽ gây ra một ngoại lệ được nêu ra khi memoization_mutator nối thêm chuỗi vào đó.
  3. Kiểm tra tất cả mã sử dụng kết quả của greeting để đảm bảo không có mã nào làm bất kỳ đột biến nào của chuỗi.

Có sự nhất trí nào về cách tiếp cận tốt nhất không? Là bất lợi duy nhất của làm (1) hoặc (2) giảm hiệu suất? (Tôi cũng nghi ngờ đóng băng một đối tượng có thể không hoạt động đầy đủ nếu nó có tham chiếu đến các đối tượng khác)

Lưu ý phụ: vấn đề này không ảnh hưởng đến ứng dụng chính của việc ghi nhớ: như là không thay đổi, tính chuỗi Fibonacci không có vấn đề với trạng thái có thể thay đổi. :)

+0

Nhận xét nhỏ về kiểu - bạn có thể đơn giản hóa phương thức chào bằng toán tử || =. Như thế này: def greeting (formality); @greeting_cache [formality] || = expensive_greeting_calculation (hình thức); end – zaius

+0

@zaius: Nó hoạt động trong hầu hết các trường hợp, nhưng sẽ không hoạt động nếu 'nil' hoặc' false' là giá trị hợp lệ. –

+0

Ah, đúng vậy. Lỗi của tôi. – zaius

Trả lời

4

Tôi sẽ dựa vào việc trả về một đối tượng nhân bản. Các hit hiệu suất của việc tạo ra một chuỗi mới là bên cạnh không có gì. Và đóng băng cho thấy chi tiết triển khai.

0

Tôi vẫn là 'người mới chơi ruby' và tôi không biết liệu bạn có nhận thức được sự khác biệt giữa phương pháp '< <' và '+' đối với Chuỗi không.

first_person = "Bob" 
puts(greeter.greeting(:casual) + " " + first_person) # => Hi Bob 
second_person = "Sue" 
puts(greeter.greeting(:casual) + " " + second_person) # => Hi Sue 

# str << obj → str 
# str + other_str → new_str 
+0

Cảm ơn bạn đã đề xuất, nhưng tôi nhiều hơn sau một giải pháp tổng quát hơn. –