【问题标题】:kotlin: lambda as an interface implementationkotlin: lambda 作为接口实现
【发布时间】:2019-10-03 22:39:48
【问题描述】:

现有 spring 的 JdbcTemplate 有签名:

public <T> List<T> query(String sql, RowMapper<T> rowMapper)

我可以用实现接口的 lambda 调用它:

jdbcTemplate.query("select ...", { rs, _ -> 5 })

但是当我在 kotlin 中声明相同的函数时:

fun <T> query(sql: String, rowMapper: RowMapper<T>): List<T> = TODO()

并尝试以相同的方式调用它:

query("select ...", { rs, _ -> 5 })

我得到一个编译错误

类型推断失败: 有趣的查询 ( sql:字符串, 行映射器:行映射器 ) : 列表 不能应用于 ( 细绳, (???, ???) → 整数 )

我要写

query("select ...", RowMapper{ rs, _ -> 5 })

为什么?有没有办法只提供 lambda?

【问题讨论】:

标签: kotlin types type-inference


【解决方案1】:

背景

在 Java 中,可以在需要 函数式接口 的上下文中传递 lambda 表达式。示例 Java 代码:

jdbcTemplate.query("select ...", (rs, _) -> 5);

在 Kotlin 中,没有从 lambda 表达式到接口的隐式转换。 Kotlin 提供了语法为 (Params) -&gt; ReturnType 的原生函数类型,而不是函数式接口。然而,为了使与 Java 的互操作性更容易,可以通过添加接口名称将 Kotlin lambda 表达式转换为 Java 函数式接口:

query("select ...", RowMapper { rs, _ -> 5 })

解决方案

不可能直接传递一个 lambda -- 但是你可以编写一个扩展函数,它接受一个函数类型并将它转发给query():

fun JdbcTemplate.query(sql: String, mapper: (A, B) -> Int) =
    query(sql, RowMapper { a, b -> mapper(a, b) })

然后可以按照您想要的方式调用它。请注意,由于 Kotlin 允许尾随 lambda 表达式的特殊语法,您不需要在所有参数周围加上括号:

jdbc.query("select ...") { rs, _ -> 5 }

另请参阅 here,我在其中详细解释了此行为。

【讨论】:

  • 不,我的每个调用都是 kotlin。包括第一个
  • 那是一个误解——我相应地编辑了我的答案。
猜你喜欢
  • 2018-06-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-31
  • 1970-01-01
  • 1970-01-01
  • 2018-11-28
  • 2020-10-17
相关资源
最近更新 更多