我对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()
。
答案 0 :(得分:2)
我在编译器中找到了一条规则:如果Java方法调用需要SAM-interfaces类型,那么你可以用lambdas(或函数)替换它们,但 all 这些参数,或没有。
所以,你有方法:public void observe(OneMethod one, Observer<T> observer)
。
两个参数都是SAM候选者。你可以打电话:
observer(object1, object2)
或:
observer(function1, function2)
但不:
observer(object1, function2)
和不:
observer(function1, object2)
即使在3个或更多参数的情况下也会出现相同的行为。 造成这种情况的原因是编译器设计中的技术难度。
对不起,如果我不是很清楚,我的英语不是很好。
答案 1 :(得分:1)
随着即将推出的新类型推断,这个问题将在Kotlin编译器中修复。现在可以在Android项目中启用实验类型推断(需要Kotlin 1.3),方法是将其添加到模块级gradle文件中:
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
kotlinOptions {
freeCompilerArgs = ["-XXLanguage:+NewInference"]
}
}
应该可以使用(但it doesn't quite work yet):
来启用它kotlin {
experimental {
newInference = "enable"
}
}
Beholder写道:
原因是编译器设计中存在技术难题
我看到它的方式,Kotlin编译器不希望为具有2^n
参数的方法生成n
变体,这些参数有资格进行SAM转换,因此它只生成两个变体:一个人都是lambdas,一个人没有lambdas
YouTrack上存在相关问题:Impossible to pass not all SAM argument as function