如何在 Kotlin 中将功能接口实现为 lambda?
How to implement a functional interface as lambda in Kotlin?
我想将功能性 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
我认为没有语言级别的选项可以执行此操作,但您可以将 "ugly" 代码抽象为辅助方法,以便在实际需要业务逻辑的地方更容易阅读:
辅助方法
fun Foo(body: (String) -> String) = object : Foo{
override fun bar(input: String)= body(input)
}
公司代码
fun createFoo():Foo {
return Foo {input:String -> "Hello $input!"}
}
要使用 Kotlin lambda 到 Java SAM 接口转换任何你想要的地方,只需在 lambda 之前指定接口的名称。
fun createFoo(): Foo {
return Foo { input:String -> "Hello $input!" }
}
甚至不需要那么长。
fun createFoo(): Foo {
return Foo { "Hello $it!" }
}
只要接口只有一个方法并在 Java 中声明,就可以了。
在你的情况下,在 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
}
或者,要对 Kotlin 也有 Foo
的感觉,您可以按如下方式进行:
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 中不可见。 Kotlin 端将更改为以下内容:
class KFactory : FooFactory {
override fun createFoo() : Foo = {
"hello $it"
}
}
Factory
接口也可以被替换:
interface FooFactory {
fun createFoo() : Foo
}
但在引擎盖下,一切都保持不变。我们在 Kotlin 中 have/use (String) -> String
和 Java.
中的 Foo
-functional-interface
I want to implement a functional kotlin interface (interface with a single abstract method) as a kotlin lambda. How to do that?
不能
It has to be implemented as object, which is ugly as hell.
确实如此。
您有两个选择:
1.) 使用typealias
typealias Foo = (String) -> String
fun createFoo(): Foo = { "Hello $it!" }
2.) 根据您的 API,您可以定义一个扩展函数,它接收函数类型 (String) -> String
作为 crossinline
参数,然后在 [=14] 中调用它=] 块。这样,您可以在给定函数中隐藏 object:
,并且在外部仍然可以使用 lambda 参数调用它。不过在这种情况下似乎不适用。
从 Kotlin v1.4 开始
1.4 版将支持 SAM 转换,并使用新的类型推理算法。
参见:
Kotlin v1.4 之前
如果伴生对象实现采用 lambda 的 invoke
函数,它就会起作用。
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!" }
Functional/SAM kotlin 中定义的接口在设计上不能作为 Kotlin lambda 实现,请参阅 KT-7770。
在 Kotlin 中,函数式/SAM 接口被视为反模式,应该声明函数类型:(String)->String
。函数类型可以表示为类型别名,使其看起来和感觉起来像一个接口:typealias Foo=(String)->String
。
注意:类型别名仅在 Kotlin 的 Java 代码中不可见!
只需将 fun
关键字添加到您的接口声明中:
fun interface Foo {
fun bar(input: String): String
}
是Kotlin函数式接口的注解(而不是Java中的@FunctionalInterface
注解)。
现在你可以这样实现了:
Foo { input: String -> "Hello $input!" }
我想将功能性 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
我认为没有语言级别的选项可以执行此操作,但您可以将 "ugly" 代码抽象为辅助方法,以便在实际需要业务逻辑的地方更容易阅读:
辅助方法
fun Foo(body: (String) -> String) = object : Foo{
override fun bar(input: String)= body(input)
}
公司代码
fun createFoo():Foo {
return Foo {input:String -> "Hello $input!"}
}
要使用 Kotlin lambda 到 Java SAM 接口转换任何你想要的地方,只需在 lambda 之前指定接口的名称。
fun createFoo(): Foo {
return Foo { input:String -> "Hello $input!" }
}
甚至不需要那么长。
fun createFoo(): Foo {
return Foo { "Hello $it!" }
}
只要接口只有一个方法并在 Java 中声明,就可以了。
在你的情况下,在 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
}
或者,要对 Kotlin 也有 Foo
的感觉,您可以按如下方式进行:
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 中不可见。 Kotlin 端将更改为以下内容:
class KFactory : FooFactory {
override fun createFoo() : Foo = {
"hello $it"
}
}
Factory
接口也可以被替换:
interface FooFactory {
fun createFoo() : Foo
}
但在引擎盖下,一切都保持不变。我们在 Kotlin 中 have/use (String) -> String
和 Java.
Foo
-functional-interface
I want to implement a functional kotlin interface (interface with a single abstract method) as a kotlin lambda. How to do that?
不能
It has to be implemented as object, which is ugly as hell.
确实如此。
您有两个选择:
1.) 使用typealias
typealias Foo = (String) -> String
fun createFoo(): Foo = { "Hello $it!" }
2.) 根据您的 API,您可以定义一个扩展函数,它接收函数类型 (String) -> String
作为 crossinline
参数,然后在 [=14] 中调用它=] 块。这样,您可以在给定函数中隐藏 object:
,并且在外部仍然可以使用 lambda 参数调用它。不过在这种情况下似乎不适用。
从 Kotlin v1.4 开始
1.4 版将支持 SAM 转换,并使用新的类型推理算法。
参见:
Kotlin v1.4 之前
如果伴生对象实现采用 lambda 的 invoke
函数,它就会起作用。
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!" }
Functional/SAM kotlin 中定义的接口在设计上不能作为 Kotlin lambda 实现,请参阅 KT-7770。
在 Kotlin 中,函数式/SAM 接口被视为反模式,应该声明函数类型:(String)->String
。函数类型可以表示为类型别名,使其看起来和感觉起来像一个接口:typealias Foo=(String)->String
。
注意:类型别名仅在 Kotlin 的 Java 代码中不可见!
只需将 fun
关键字添加到您的接口声明中:
fun interface Foo {
fun bar(input: String): String
}
是Kotlin函数式接口的注解(而不是Java中的@FunctionalInterface
注解)。
现在你可以这样实现了:
Foo { input: String -> "Hello $input!" }