7

Tôi bối rối hơn nhà xây dựng SAM, tôi có lớp này Java:Không thể thay thế SAM-constructor với lambda khi số đầu tiên là một lớp học với một phương pháp

public class TestSam<T> { 

    public void observe(ZeroMethods zero, Observer<T> observer) { 
    } 

    public void observe(OneMethod one, Observer<T> observer) { 
    } 

    public void observe(TwoMethods two, Observer<T> observer) { 
    } 

    public interface Observer<T> { 
     void onChanged(@Nullable T t); 
    } 

    public interface ZeroMethods { 
    } 

    public interface OneMethod { 
     First getFirst(); 
    } 

    public interface TwoMethods { 
     First getFirst(); 

     Second getSecond(); 
    } 

    public interface First { 
    } 

    public interface Second { 
    } 
} 

Và mã Kotlin này:

fun testSam(
     test: TestSam<String>, 
     zero: TestSam.ZeroMethods, 
     one: TestSam.OneMethod, 
     two: TestSam.TwoMethods 
) { 
    test.observe(zero) { println("onChanged $it") } // 1. compiles 
    test.observe(zero, TestSam.Observer { println("onChanged $it") }) // 2. Redundant SAM-constructor 

    test.observe(one) { println("onChanged $it") } // 3. doesn't compile 
    test.observe({ one.first }) { println("onChanged $it") } // 4. compiles 
    test.observe(one, TestSam.Observer { println("onChanged $it") }) // 5. compiles 

    test.observe(two) { println("onChanged $it") } // 6. compiles 
    test.observe(two, TestSam.Observer { println("onChanged $it") }) // 7. Redundant SAM-constructor 
} 

Thỏa thuận ở đây là gì? Tại sao Kotlin không thể tìm ra 3. (và cung cấp biến thể đặc biệt 4.), nhưng xử lý tất cả các trường hợp khác?


Lý do cho mã này là LiveData<T>.observe(LifecycleOwner owner, Observer<T> observer) phương pháp trong Android, nơi LifecycleOwner có một phương pháp getLifecycle().

Trả lời

2

Tôi tìm thấy một quy tắc trong trình biên dịch: nếu Java gọi phương thức đòi hỏi loại đó là SAM-giao diện, sau đó bạn có thể thay thế chúng với lambdas (hoặc chức năng), nhưng hoặc tất cả thông số như vậy, hay không của họ.

Vì vậy, bạn có phương thức: public void observe(OneMethod one, Observer<T> observer). Cả hai tham số đều là ứng viên SAM. Bạn có thể gọi:
observer(object1, object2)
hay:
observer(function1, function2)

nhưng không:
observer(object1, function2)
không:
observer(function1, object2)

hành vi tương tự sẽ được ngay cả trong trường hợp của 3 hoặc nhiều thông số hơn. Nguyên nhân của điều này là khó khăn về mặt kỹ thuật trong thiết kế trình biên dịch.

Xin lỗi nếu tôi không rõ ràng, tôi không giỏi tiếng Anh.

+0

Bạn có thể thêm liên kết vào mã nguồn trình biên dịch không? (hoặc một đặc điểm kỹ thuật mà điều này được giải thích?) (Hoặc bạn có tìm thấy câu trả lời bằng cách thử nó không?) – Marco13

+0

Tôi nghĩ rằng nó không thực sự tài liệu, chỉ cần cố gắng ra bản thân mình. Để cụ thể hơn, tốt hơn là hỏi các nhà phát triển Kotlin. Một trong số họ nói với tôi rằng có một vấn đề trong trình theo dõi lỗi cho điều đó. – Beholder

+0

Ồ, tôi nghĩ tôi hiểu điều đó. Vì vậy, vấn đề là 'OneMethod' và 'LifecycleOwner' của Android là các giao diện SAM. Thật tệ, đó chỉ là tình cờ, thực sự, bởi vì tôi nghi ngờ 'LifecycleOwner' được sử dụng theo cách' Runnable' được sử dụng, chúng ta sẽ không bao giờ định nghĩa các lớp ẩn danh cho nó trong Java, thay vào đó giao diện được thực hiện bởi 'AppCompatActivity' lớp cơ sở. – arekolek

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