如何在kotlin中将lambdas与函数式接口一起使用并直接将lambda分配给var

Posted

技术标签:

【中文标题】如何在kotlin中将lambdas与函数式接口一起使用并直接将lambda分配给var【英文标题】:How to use lambdas together with functional interfaces and directly assign lambda to var in kotlin 【发布时间】:2021-06-29 21:07:19 【问题描述】:

我有这个代码:

package org.medianik.kotlindoc

fun main()
    val creator:Creatable = toCreatable(::Created)// Ok. Compiles, and works fine
    val creator1:Creatable = ::Created // Compilation error
    val creator2:Creatable = ::Created as Creatable // ok enough to compile, but there is runtime exception
    val c = creator.create(5)
    val creator3:Creatable = toCreatable(c::doSmth1) // Ok. Compiles, works fine
    val creator4:Creatable = c::doSmth1 // Compilation error
    val creator5:Creatable = c::doSmth1 as Creatable // Again ok enough to compile, but there is runtime exception
    val creator6:Creatable = Creatable  i -> Created(i)  // Works fine, but that's not what I want


fun toCreatable(c:Creatable) = c

fun interface Creatable
    fun create(i: Int) : Created

class Created(private var i: Int)
    fun doSmth1(add: Int): Created
        return this.also  i+=add 
    

creator2 的例外情况:

Exception in thread "main" java.lang.ClassCastException: class org.medianik.kotlindoc.MainKt$main$creator2$1 cannot be cast to class org.medianik.kotlindoc.Creatable (org.medianik.kotlindoc.MainKt$main$creator2$1 and org.medianik.kotlindoc.Creatable are in unnamed module of loader 'app')

creator5 例外:

Exception in thread "main" java.lang.ClassCastException: class org.medianik.kotlindoc.MainKt$main$creator5$1 cannot be cast to class org.medianik.kotlindoc.Creatable (org.medianik.kotlindoc.MainKt$main$creator5$1 and org.medianik.kotlindoc.Creatable are in unnamed module of loader 'app')

我不知道如何使 creator1/4 与方法引用一起工作。有什么方法可以让它们工作吗?因为这对我来说似乎毫无意义:如果您将方法引用作为参数传递给函数——它会转换为接口,否则不会。它是如何工作的?

对于接口的函数是否有一些特殊的转换?

【问题讨论】:

【参考方案1】:

我将您的代码复制到 IntelliJ 中,但行中也出现错误

 val creator:Creatable = toCreatable(::Created)
 val creator3:Creatable = toCreatable(c::doSmth1)

问题是,Creatable 是一个命名接口,它与类 Created 具有相同的方法签名,但这个类没有实现接口。

请注意,即使有签名,函数也不会实现接口。

您可以 decare 函数类型而不是接口。请注意,这并不相同,但它们的处理方式几乎相同。

typealias Creatable = (Int) -> Created

或者您可以编写一个接受此类函数类型的包装器:

fun toCreatable(c:(Int) -> Created) = object: Creatable 
    override fun create(i: Int): Created 
        return c(i)
    

这个函数接受一个函数并返回一个实际实现接口的对象。

【讨论】:

是的,我知道 typealias。正如 kotlinlang.org 所说:函数式接口与类型别名函数式接口和类型别名有不同的用途。类型别名只是现有类型的名称——它们不会创建新类型,而函数式接口会。类型别名只能有一个成员,而功能接口可以有多个非抽象成员和一个抽象成员。功能接口也可以实现和扩展其他接口。考虑到上述情况,函数式接口比类型别名更灵活并提供更多功能。 所以我想知道是否有在 lambda 上下文中使用接口的捷径(就好像它是 typealias)。

以上是关于如何在kotlin中将lambdas与函数式接口一起使用并直接将lambda分配给var的主要内容,如果未能解决你的问题,请参考以下文章

Kotlin学习与实践 带接收者的lambda及Java的函数式接口

Kotlin学习与实践 Lambda

lambda表达式与函数式(FunctionalInterface)接口

为什么在Kotlin中将变量传递给lambda有效?

Kotlin之高阶函数

初识函数式编程与函数式接口