2010-01-15 30 views
7

Trong SO question 2068165 một câu trả lời đưa ra ý tưởng sử dụng một cái gì đó như thế này:Đây có phải là cách sử dụng hợp lý cho && = trong Ruby không?

params[:task][:completed_at] &&= Time.parse(params[:task][:completed_at]) 

như một cách máy sấy nói

params[:task][:completed_at] = Time.parse(params[:task][:completed_at]) if params[:task][:completed_at] 

nơi Hash params sẽ được phát ra từ một hình thức (Rails/ActionView) .

Đó là một loại hệ quả đối với thành ngữ nổi tiếng ||=, đặt giá trị nếu LHS là không nil/false.

Được sử dụng &&= như thế này thực sự là một thành ngữ Ruby được công nhận mà tôi đã bỏ lỡ bằng cách nào đó hoặc có tôi chỉ quên một thành ngữ thường được sử dụng hơn? Nó nhận được khá muộn ...

+0

Các phân tích cú pháp không một số công cụ kỳ lạ: a = 1 nếu một công trình ** ** và b = 1 nếu không bao giờ thất bại ** ** –

+0

để thêm xúc phạm vào thương tích nếu xxx; xxx = 1; kết thúc ** không thành công ** –

Trả lời

5

Nó nên được. Nếu không có gì khác, params[:task] chỉ được đánh giá một lần khi sử dụng biểu mẫu &&=.

Để làm rõ:

params[:task][:completed_at] = params[:task][:completed_at] && ... 

cuộc gọi [](:task) trên params hai lần, [](:completed_at)[]=(:completed_at) một lần mỗi ngày params[:task].

params[:task][:completed_at] &&= ... 

gọi [](:task) trên params một lần, và giá trị của nó được giấu đi cho cả [](:completed_at)[]=(:completed_at) cuộc gọi.


ví dụ thực tế mô tả những gì tôi đang cố gắng để minh họa (dựa trên mã ví dụ Marc-Andre của; nhiều nhờ):

class X 
    def get 
    puts "get" 
    @hash ||= {} 
    end 
end 

irb(main):008:0> x = X.new 
=> #<X:0x7f43c496b130> 
irb(main):009:0> x.get 
get 
=> {} 
irb(main):010:0> x.get[:foo] = 'foo' 
get 
=> "foo" 
irb(main):011:0> x.get[:foo] 
get 
=> "foo" 
irb(main):012:0> x.get[:foo] &&= 'bar' 
get 
=> "bar" 
irb(main):013:0> x.get[:foo] = x.get[:foo] && 'bar' 
get 
get 
=> "bar" 

Lưu ý rằng việc sử dụng các "mở rộng" hình thức gây "nhận được" để được in ra hai lần, nhưng bằng cách sử dụng hình thức nhỏ gọn làm cho nó chỉ được in một lần.

+0

Câu trả lời của bạn không chính xác. Cả hai hình thức là tương đương và params [: task] [: completed_at] được đánh giá hai lần (giả sử sự thật của nó) (xem câu trả lời của tôi). –

+0

Tôi nghĩ tôi cần làm rõ chính xác những gì tôi đang trả lời. :-P –

+0

Tôi bằng cách nào đó muốn bạn đã đúng, nhưng không, [: task] getter cũng sẽ được thực hiện nhiều lần trong biểu mẫu && = dưới dạng 'if'. Tôi đã cập nhật câu trả lời của mình để hiển thị điều này. –

1

Sử dụng &&=, trong trường hợp LHS sai, chỉ được đọc một lần, nhưng không được đặt. Điều này sẽ làm cho nó rõ ràng hơn ...

class Test 
    def initialize(value) 
    @v = value 
    end 
    def v=(value) 
    puts "set" 
    @v = value 
    end 
    def v 
    puts "get=>#{@v}" 
    @v 
    end 
end 
t = Test.new(true) 

t.v = t.v && true 
puts '----' 

t.v &&= true 
puts '----' 

t = Test.new(false) # lets make LHS false 
t.v = t.v && true 
puts '----' 

t = Test.new(false) # lets make LHS false 
t.v &&= true 

Kết quả:

get=>true 
set 
---- 
get=>true 
set 
---- 
get=>false 
set 
---- 
get=>false 
+0

Khi LHS sai, điều đó tốt: chúng tôi không muốn đặt nó nếu không có, nhưng chúng tôi có thể cần chuyển đổi/xác thực/phân tích cú pháp nếu nó hiện diện nhưng không ở dạng chúng tôi thực sự muốn, ví dụ: nơi chúng ta có được một ngày/thời gian như một chuỗi và muốn chuyển nó vào một mô hình theo kiểu mà nó mong đợi. –

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