将函数传递给Kotlin中的函数

时间:2017-04-11 05:10:02

标签: lambda kotlin currying

我开始在Kotlin中使用Vaadin,并创建了以下扩展方法:

fun AbstractComponentContainer.addButton(buttonText : String = "", icon : FontIcon? = null, function : (() -> Unit)? = null) {
    val button = Button(buttonText)
    if (icon != null) {
    button.icon = icon
    }
    if (function!=null) {
    button.addClickListener { function() }
    }
    this.addComponent(button)
}

这允许我向容器添加一个按钮,带有可选的点击监听器(和一个可选图标)。

我现在想要为组件添加两个按钮,一个用于向上,一个用于向下,以允许我在列表中上下移动项目。因此,我想两次致电addButton()。 lambda中的逻辑将是相同的,唯一的区别在于,一个项目的位置将递增而另一个递减。

我正在尝试创建一个可以传递给addClickListener的函数,并且为了保存我编写两个几乎完全相同的函数,我希望能够向该函数传递对{的引用{1}}和Long::plusAssign

我无法让它发挥作用。要么它不会编译,要么在运行时得到Long::minusAssign

这是我必须去的地方:

ClassCastException

如果我删除演员表,它将无法编译,如果我离开演员表,我会得到以下内容:

val function = { function: (Long) -> Long ->
    val selectedItems: MutableSet<Item> = //get my items
    if (selectedItems.size == 1) {
        val elementAt = selectedItems.elementAt(0)
        elementAt.position = function(elementAt.position)
        Notification("Element's position is now ${elementAt.position}", "", Notification.Type.HUMANIZED_MESSAGE, true).show(Page.getCurrent())
        listDataProvider.refreshItem(elementAt)
    }
}
buttonLayout.addButton(buttonText = "Up", function = function(Long::inc) as (()->Unit)?)
buttonLayout.addButton(buttonText = "Down", function = function(Long::dec) as (()->Unit)?)

有没有办法实现我想要的?我真的不想改变java.lang.ClassCastException: kotlin.Unit cannot be cast to kotlin.jvm.functions.Function0 所期望的函数的签名。

(注意这是一个关于Kotlin的问题,而不是关于Vaadin的问题,所以我要离开Vaadin标签)

2 个答案:

答案 0 :(得分:3)

您要求的是currying,Kotlin不支持。解决方法是显式创建新的lambdas:

buttonLayout.addButton("Up", function = { function(Long::inc) })
buttonLayout.addButton("Down", function = { function(Long::dec) })

答案 1 :(得分:0)

我不同意Voddan的解决方案,这似乎是解决我们不应该遇到的问题的一种技巧。

编译器告诉我function正在返回Unit而不是() -> Unit。这似乎是合乎逻辑的,所以只需创建一个函数而不是Unit

val function = fun(longFunction: (Long) -> Long) = {
    val selectedItems: MutableSet<Item> = //get my items
    if (selectedItems.size == 1) {
        val elementAt = selectedItems.elementAt(0)
        elementAt.position = longFunction(elementAt.position)
        Notification("Element's position is now ${elementAt.position}", "", Notification.Type.HUMANIZED_MESSAGE, true).show(Page.getCurrent())
        listDataProvider.refreshItem(elementAt)
    }
}

这样你就可以做到:

buttonLayout.addButton("Up", function = function(Long::inc))
buttonLayout.addButton("Down", function = function(Long::dec))

在某些情况下,出于可读性的目的,我有时会更喜欢更明确/天真的解决方案(这是讨好吗?):

val function = fun(longFunction: (Long) -> Long): () -> Unit {
    return fun() {
        val selectedItems: MutableSet<Item> = //get my items
        if (selectedItems.size == 1) {
            val elementAt = selectedItems.elementAt(0)
            elementAt.position = longFunction(elementAt.position)
            Notification("Element's position is now ${elementAt.position}", "", Notification.Type.HUMANIZED_MESSAGE, true).show(Page.getCurrent())
            listDataProvider.refreshItem(elementAt)
        }
    }
}

在我这方面,它给出了相同的结果,我觉得它更自然地阅读,对于从Kotlin开始的开发人员来说更容易。我不知道它是否是一种曲目,但是它正在编写并在我身边工作(通过模拟Vaadin的课程/事件来测试)。