将函数传递给Kotlin中的函数

我开始和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 ,并保存我写两个函数做几乎相同的事情,我希望能够传递给该函数的引用Long::plusAssignLong::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 

有没有办法实现我想要的? 我真的不想改变addButton预期的函数的签名。

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

你所要求的是咖喱 ,而这在Kotlin中是不被支持的。 解决方法是显式创建新的lambda表达式:

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

我不同意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)) 

在某些情况下,为了便于阅读,我有时候会更喜欢一个更加明确的/天真的解决方案(这是否是currying?):

 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的类/事件来测试)。

Interesting Posts