如何从 Kotlin 接口创建 lambda 表达式?

Mig*_*noz 14 kotlin

我有一个简单的 Kotlin 界面:

@FunctionalInterface
interface ServiceMethod<T> {
  fun doService(): T
}
Run Code Online (Sandbox Code Playgroud)

尽管名称如此,但这本质上与 Java 的供应商功能接口相同。唯一的区别是我可以实现Supplier,而不能实现自己的。

val supplier = Supplier<String> {
  "Hello"
}
val serviceMethod = ServiceMethod<String> {
  "Hello"
}
Run Code Online (Sandbox Code Playgroud)

ServiceMethod 实现给了我一个编译器错误,提示“接口 ServiceMethod 没有构造函数”。嗯?当然不是!这是一个功能界面。

我知道我可以把它写成一个匿名内部类:

val serviceMethod = object : ServiceMethod<String> {
  override fun doService(): String {
    return "Hello"
  }
}
Run Code Online (Sandbox Code Playgroud)

但这要冗长得多。在这种情况下,我可以只使用供应商接口,但这不适用于其他接口。我不应该用 Java 编写接口,只是为了能够在 Kotlin 中使用 lambda。我宁愿为我所有的 Kotlin 接口使用 lambda,尤其是因为我将编写很多这样的接口。我错过了一些明显的东西吗?

Sam*_*Sam 20

fun从 Kotlin 1.4 开始使用interface 修饰符

在 Kotlin 1.3 及更早版本中,Supplier仅 Java 接口支持SAM(单一抽象方法)转换,您可以在其中像使用 lambda 函数一样实例化接口。

语言设计者最初认为SAM 转换对 Kotlin 接口没有用,因为Kotlin 函数已经有一个 type。例如,您的doService函数的类型可以写为() -> T. 您可以简单地编写,而不是创建一个实现接口的对象:

val serviceMethod: () -> String = { "Hello" }
Run Code Online (Sandbox Code Playgroud)

Kotlin 1.4 为 Kotlin 接口添加了 SAM 转换,但它并不是对每个接口都开箱即用。相反,您必须将特殊fun修饰符应用于 Kotlin 接口以使其符合 SAM 转换的条件。

在您的示例中,它看起来像这样:

fun interface ServiceMethod<T> {
  fun doService(): T
}
Run Code Online (Sandbox Code Playgroud)

添加修饰符后,您可以完全按照您在问题中的希望使用 lambda 创建一个实例。

val serviceMethod = ServiceMethod<String> { "Hello" }
Run Code Online (Sandbox Code Playgroud)

您可以在功能接口Kotlin 文档中了解更多信息。

  • 这个名字很适合回答这样的问题 (2认同)