我想将功能性kotlin接口(具有单个抽象方法的接口)实现为kotlin lambda。该怎么做?
Kotlin界面
@FunctionalInterface
interface Foo{
fun bar(input: String): String
}
Kotlin实施。
fun createFoo(): Foo {
return { input: String -> "Hello $input!" }
}
↑不编译↑
它必须作为对象来实现,这很难看。
fun createFoo() =
object : Foo{
override fun bar(input: String)= "Hello $input"
}
编辑:从Java到kotlin纠正了我的示例界面
答案 0 :(得分:2)
我想将功能性kotlin接口(具有单个抽象方法的接口)实现为kotlin lambda。该怎么做?
不能
它必须作为对象来实现,这很难看。
确实。
您有两个选择:
1。)使用typealias
typealias Foo = (String) -> String
fun createFoo(): Foo = { "Hello $it!" }
2。),具体取决于您的API,您可以定义一个扩展函数,该扩展函数以(String) -> String
参数的形式接收功能类型crossinline
,然后在object: __
块内调用它。这样,您可以将object:
隐藏在给定的函数中,并且在外部仍然可以使用lambda参数来调用它。不过,在这种情况下似乎并不适用。
答案 1 :(得分:1)
我认为没有语言级别的选项可以执行此操作,但是您可以将“丑陋的”代码抽象为一个辅助方法,以便在实际需要业务逻辑的地方更容易阅读:
帮助方法
fun Foo(body: (String) -> String) = object : Foo{
override fun bar(input: String)= body(input)
}
公司代码
fun createFoo():Foo {
return Foo {input:String -> "Hello $input!"}
}
答案 2 :(得分:1)
在您的情况下,使用Java接口会更容易:
fun createFoo() : Foo = Foo { "hello $it" }
但是,因为有了Kotlin界面,您在这里有点不走运。这是与此相关的问题:KT-7770
对此的一种解决方法是(但主要取决于您如何使用该接口)具有如下所示的Kotlin接口,它是Java端的主要入口点:
interface Foo : (String) -> String
在Kotlin端,您将不会使用它,而在Java端,则应仅使用它来交付功能,例如
// Java class
public class JFooFactory implements FooFactory {
@Override
@NotNull
public Foo createFoo() { // uses the Foo-interface from Kotlin
return input -> "hello " + input;
}
}
// Kotlin equivalent:
class KFactory : FooFactory {
override fun createFoo() : (String) -> String = {
"hello $it"
}
}
对应的FooFactory
-接口可能如下所示:
interface FooFactory {
fun createFoo() : (String) -> String
}
用法可能如下:
listOf(KFooFactory(), JFooFactory())
.map {
it.createFoo()
}
.forEach { func : (String) -> String -> // i.e. func is of (sub)type (String) -> String
func("demo") // calling it to deliver "hello demo" twice
}
或者,也可以让Foo
感觉像Kotlin一样:
typealias Foo = (String) -> String
interface JFoo : Foo
// or if you put the interface in its own package you could also use:
interface Foo : someother.package.Foo
然后,Java代码与上面的相同,其中JFoo
或Foo
指向另一个软件包;从Java中看不到typealias。 Kotlin方面将更改为以下内容:
class KFactory : FooFactory {
override fun createFoo() : Foo = {
"hello $it"
}
}
Factory
-接口也可以替换:
interface FooFactory {
fun createFoo() : Foo
}
在引擎盖下,所有东西保持不变。我们在Kotlin中使用过(String) -> String
,在Java中使用过Foo
-functional-interface。
答案 3 :(得分:1)
只需将 fun
关键字添加到您的接口声明中:
fun interface Foo {
fun bar(input: String): String
}
它是 Kotlin 中函数式接口的表示法(而不是 Java 中的 @FunctionalInterface
注释)。
现在你可以像这样实现它:
Foo { input: String -> "Hello $input!" }
答案 4 :(得分:0)
要在任何需要的地方使用Kotlin lambda到Java SAM接口的转换,只需在lambda之前指定接口的名称即可。
fun createFoo(): Foo {
return Foo { input:String -> "Hello $input!" }
}
它甚至不需要那么长。
fun createFoo(): Foo {
return Foo { "Hello $it!" }
}
只要接口只有一个方法并且用Java声明,这就是您要做的所有事情。
答案 5 :(得分:0)
如果伴随对象实现invoke
函数并使用lambda,则该函数有效。
Kotlin界面
interface Foo{
fun bar(input: String): String
companion object {
inline operator fun invoke(crossinline function: (String) -> String) =
object : Foo{
override fun bar(input: String) = function(input)
}
}
}
Kotlin实施
fun createFoo()= Foo { input: String -> "Hello $input!" }
kotlin中定义的功能/ SAM接口无法通过设计实现为Kotlin lambda,请参见KT-7770。
在Kotlin中,将功能/ SAM接口视为反模式,应声明功能类型:(String)->String
。函数类型可以表示为类型别名,以使其外观和感觉像一个接口:typealias Foo=(String)->String
。
注意:仅在Kotlin中,typealias在Java代码中不可见!