当第一个参数是具有一个方法的类时,无法用lambda替换SAM-constructor

2020年4月25日 27点热度 0条评论

我对SAM构造函数感到困惑,我有这个Java类:

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 {
    }
}

这段Kotlin代码:

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
}

怎么了为什么Kotlin无法弄清楚3.(并提供了特殊的变体4.),却能处理所有其他情况?

此代码的基本原理是Android中的
LiveData<T>.observe(LifecycleOwner owner, Observer<T> observer)方法,其中
LifecycleOwner具有一种方法
getLifecycle()

解决方案如下:

我在编译器中找到了一条规则:如果Java方法调用要求使用类型为SAM接口(interface)的类型,则可以将它们替换为lambdas(或函数),,所有这样的参数,或不包含它们的

因此,您有了方法:public void observe(OneMethod one, Observer<T> observer)
这两个参数都是SAM候选。您可以致电:observer(object1, object2)要么:observer(function1, function2)
但是不是:observer(object1, function2)而不是:observer(function1, object2)
即使在3个或更多参数的情况下,相同的行为也是如此。
原因是编译器设计中的技术困难。

抱歉,如果我不太清楚,我的英语不太好。