我开始在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标签)
答案 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的课程/事件来测试)。