如何在Kotlin中实现lambda功能接口?

如何在Kotlin中实现lambda功能接口?,kotlin,lambda,functional-interface,Kotlin,Lambda,Functional Interface,我想实现一个功能性的kotlin接口(带有一个抽象方法的接口)作为kotlin lambda。怎么做 Kotlin接口 @FunctionalInterface interface Foo{ fun bar(input: String): String } fun createFoo():Foo { return Foo {input:String -> "Hello $input!"} } interface Foo{ fun bar(input: String): S

我想实现一个功能性的kotlin接口(带有一个抽象方法的接口)作为kotlin lambda。怎么做

Kotlin接口

@FunctionalInterface
interface Foo{
  fun bar(input: String): String 
}
fun createFoo():Foo {
  return Foo {input:String -> "Hello $input!"}
}
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 {
   return { input: String -> "Hello $input!" }
}
↑ 不编译↑

它必须作为对象来实现,这非常难看

fun createFoo() = 
     object : Foo{
            override fun bar(input: String)= "Hello $input"
     }


编辑:更正了我从java到kotlin的示例接口

我认为没有语言级别的选项可以做到这一点,但您可以将“丑陋”的代码抽象到帮助器方法中,以便在实际需要业务逻辑的地方更容易阅读:

助手方法

fun Foo(body: (String) -> String) = object : Foo{
  override fun bar(input: String)= body(input)
}
业务代码

@FunctionalInterface
interface Foo{
  fun bar(input: String): String 
}
fun createFoo():Foo {
  return Foo {input:String -> "Hello $input!"}
}
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 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接口,因此您在这里有点运气不佳。以下是与此相关的一个问题:

解决这个问题的一个办法是(但这主要取决于您如何使用该接口),将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"
  }
}
其中对应的
foodfactory
-接口可能如下所示:

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
     }
用法可能如下所示:

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
指向另一个包;typealias在Java中不可见。Kotlin侧将更改为以下内容:

class KFactory : FooFactory {
  override fun createFoo() : Foo = {
    "hello $it"
  }
}
工厂
-接口也可以更换:

interface FooFactory {
  fun createFoo() : Foo
}
但在引擎盖下,一切都保持不变。我们在Kotlin中使用了
(String)->String
,在Java中使用了
Foo
-功能接口

我想实现一个功能性的kotlin接口(带有一个抽象方法的接口)作为kotlin lambda。怎么做

不能

它必须作为对象来实现,这非常难看

fun createFoo() = 
     object : Foo{
            override fun bar(input: String)= "Hello $input"
     }
的确如此


您有两个选择:

1.)使用
typealias

typealias Foo = (String) -> String

fun createFoo(): Foo = { "Hello $it!" }
2.)根据您的API,您可以定义一个扩展函数,该函数将函数类型
(String)->String
作为
交叉内联
参数接收,然后在
对象内调用它:\uuuu
块。这样,您就可以在给定函数中隐藏
对象:
,并且在外部仍然可以使用lambda参数调用它。但在这种情况下似乎不适用。

因为Kotlin v1.4 版本1.4将支持SAM转换,并使用新的类型推断算法

见:


Kotlin v1.4之前 如果伴生对象使用lambda实现
invoke
函数,则该函数有效

Kotlin接口

@FunctionalInterface
interface Foo{
  fun bar(input: String): String 
}
fun createFoo():Foo {
  return Foo {input:String -> "Hello $input!"}
}
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 lambdas,请参阅

在Kotlin中,函数/SAM接口被视为反模式,应该声明函数类型:
(String)->String
。函数类型可以表示为typealias,使其看起来和感觉像一个接口:
typealias Foo=(String)->String


注意:typealias在Java代码中不可见,仅在Kotlin中可见

只需在界面声明中添加
fun
关键字即可:

fun interface Foo {
    fun bar(input: String): String 
}
它是Kotlin中函数接口的表示法(而不是Java中的
@functioninterface
注释)

现在您可以这样实现它:

Foo { input: String -> "Hello $input!" }

我更新了我的问题,接口是在kotlin中定义的,而不是在java中定义的。@Chriss,此解决方案适用于在kotlin中定义的接口。但是,您可以通过向
Foo
函数添加
inline
修饰符使它变得更好:
inline fun Foo(crossinline body:(String)->String)=object:Foo{…}
。它将阻止在创建
Foo
期间创建额外的
(String)->String
实例。另外,当您使用此函数时,不必显式指定参数的类型,以下操作将起作用:
Foo{input->“Hello$input!”}
以及
Foo{“Hello$it!”}
。我更新了我的问题,接口是在kotlin中定义的,而不是java。不允许对kotlin接口进行SAM转换。引用文档:“请注意,此功能[SAM转换]仅适用于Java互操作;由于Kotlin具有适当的函数类型,因此不需要将函数自动转换为Kotlin接口的实现,因此不受支持。”以下是与此相关的问题: