You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Slick/Scala传递TableQuery参数出现奇怪类型错误,注入则正常

问题分析:柯里化Slick持久化函数的类型不匹配错误

嘿,这个问题其实是个很容易踩的括号优先级坑!咱们一步步拆解来看:

核心原因:方法调用顺序被括号搞反了

你的柯里化代码里,returning方法的调用括号位置写错了!Slick的returning API逻辑是先指定要返回的列,再执行插入操作,但你现在的写法把+=的结果当成了returning的参数,直接搞反了调用顺序。

看你出错的代码行:

val action = clients.returning(
  clients.map(_.clientId) += toRow(info)
)

这里的括号把clients.map(_.clientId) += toRow(info)整个包了起来,相当于先执行插入操作(返回类型是DBIOAction[ClientRow, ...]),再把这个结果传给returning——但returning期望接收的是要返回的列(比如clients.map(_.clientId),类型是Rep[Long]),这就直接导致了类型不匹配:编译器看到你传了个ClientRow相关的对象,却需要Long类型的列定义,自然报错。

而你在类里注入依赖的版本,括号位置是完全正确的:

val action = clients.returning(clients.map(_.clientId)) += toRow(info)

这里returning(clients.map(_.clientId))先构建出支持返回指定列的查询对象,再链式调用+=执行插入,完全符合Slick的API设计,所以编译正常。

修正后的柯里化函数

只需要调整括号位置,把+= toRow(info)移到returning调用的外面就行:

val persist: PersistClient[ClientTable] = db => clients => info => {
  val action = clients.returning(clients.map(_.clientId)) += toRow(info)
  db.run(action).map(constructId(_))
}

修正后,returning会先拿到要返回的clientId列,再执行插入操作,此时action的类型是DBIOAction[Long, NoStream, Effect.Write],正好和后续db.run以及constructId的类型要求匹配,编译错误就消失了。

为啥类注入版本没这个问题?

说白了就是括号优先级的锅:类注入的代码里,你正确拆分了方法调用步骤,而柯里化版本的括号错误改变了代码的执行逻辑,把插入操作的结果传给了本应接收列定义的returning方法,才触发了类型不匹配的错误。

内容的提问来源于stack exchange,提问作者Nimrod Sadeh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 08:26:53