2012-08-30 16 views
8

Tôi đã vấp phải thứ gì đó có đóng cửa Groovy và các đại biểu mà tôi không chắc chắn là một phần chính thức của ngôn ngữ hoặc thậm chí là một lỗi. Về cơ bản tôi xác định một đóng cửa mà tôi đọc trong như một chuỗi từ một nguồn bên ngoài, và một trong các biến trong lớp xác định việc đóng cửa cần phải được sửa đổi bởi việc đóng cửa. Tôi đã viết một ví dụ đơn giản cho thấy những gì tôi tìm thấy công trình và những gì không hoạt động.Để có một đóng cửa groovy để sửa đổi một biến được định nghĩa trong phạm vi của một đại biểu, bạn cần phải xác định rõ ràng delegate.theVariableName?

Nếu bạn nhìn vào mã kiểm tra bên dưới, bạn sẽ thấy một lớp định nghĩa một biến

animal = "cat" 

và hai đóng cửa được xác định một cách nhanh chóng từ chuỗi mà cố gắng để thay đổi biến động vật.

này hoạt động>

String code = "{ -> delegate.animal = 'bear'; return name + 'xx' ; }" 

Nhưng điều này không

String code = "{ -> animal = 'bear'; return name + 'xx' ; }" 

Nó có vẻ như tôi cần phải hội đủ điều kiện rõ ràng biến to-be-sửa đổi của tôi với 'đại biểu.' để làm việc này. (Tôi đoán tôi cũng có thể xác định một setter trong lớp kèm theo cho việc đóng cửa để gọi để sửa đổi giá trị.)

Vì vậy .... Tôi đã tìm ra cách để thực hiện công việc này, nhưng tôi muốn quan tâm nếu ai đó có thể chỉ cho tôi một số tài liệu hấp dẫn giải thích các quy tắc đằng sau điều này.

Cụ .... tại sao sự phân công đơn giản

animal = 'bear' 

sẽ ảnh hưởng đến các biến ban đầu? Có bản sao bóng được làm ở đây hay gì đó không?

import org.junit.Test 

/* 
* Author: cbedford 
* Date: 8/30/12 
* Time: 1:16 PM 
*/ 

class GroovyTest { 
    String animal = "cat" 
    String name = "fred" 

    @Test 
    public void testDelegateWithModificationOfDelegateVariable() { 
    String code = "{ -> delegate.animal = 'bear'; return name + 'xx' ; }" 
    def shell = new GroovyShell() 
    def closure = shell.evaluate(code) 

    closure.delegate = this 
    def result = closure() 

    println "result is $result" 
    println "animal is $animal" 

    assert animal == 'bear' 
    assert result == 'fredxx' 
    } 


    // This test will FAIL. 
    @Test 
    public void testDelegateWithFailedModificationOfDelegateVariable() { 
    String code = "{ -> animal = 'bear'; return name + 'xx' ; }" 
    def shell = new GroovyShell() 
    def closure = shell.evaluate(code) 

    closure.delegate = this 
    def result = closure() 

    println "result is $result" 
    println "animal is $animal" 

    assert animal == 'bear' 
    assert result == 'fredxx' 
    } 
} 

Trả lời

7

đóng cửa Groovy có five strategies cho việc giải quyết những biểu tượng bên trong đóng cửa:

  • OWNER_FIRST: chủ sở hữu (nơi đóng cửa được xác định) sẽ được kiểm tra đầu tiên, sau đó các đại biểu
  • OWNER_ONLY: chủ sở hữu sẽ được kiểm tra , đại biểu chỉ được kiểm tra nếu được tham chiếu rõ ràng
  • DELEGATE_FIRST: đại biểu được chọn trước, sau đó chủ sở hữu
  • DELEGATE_ONLY: các đại biểu sẽ được kiểm tra đầu tiên, chủ sở hữu chỉ được kiểm tra nếu tham chiếu rõ ràng
  • TO_SELF: không phải đại biểu cũng không chủ sở hữu được kiểm tra

Mặc định là OWNER_FIRST. Vì việc đóng được định nghĩa động, chủ sở hữu của bạn là một đối tượng Script có các quy tắc đặc biệt. Viết animal = 'bear' trong Tập lệnh sẽ thực sự tạo một ràng buộc mới có tên là animal và gán 'bear' cho nó.

Bạn có thể sửa các bài kiểm tra của bạn để làm việc mà không tham khảo một cách rõ ràng đại biểu bằng cách đơn giản thay đổi chiến lược quyết tâm về việc đóng cửa trước khi gọi nó với:

closure.resolveStrategy = Closure.DELEGATE_FIRST 

Điều này sẽ tránh các lẻ các Script ràng buộc và sử dụng các đại biểu như mong đợi .

+0

Điều đó có ý nghĩa hoàn hảo. và nhanh quá; ^). Cảm ơn nhiều. –

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