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

Scala 3.6.3中upickle ReadWriter处理Array类型编译失败求助

Scala 3 + uPickle 数组类型序列化歧义问题解决

问题代码

case class LichessDuels(id: String, p: Array[LichessDuelInterna]) derives ReadWriter
  
case class LichessDuelInterna(n: String, r: Int, k: Int) derives ReadWriter

编译错误信息

case class LichessDuels(id: String, p: Array[LichessDuelInterna]) derives ReadWriter
[error]     |                                                                            ^
[error]     |No best given instance of type WritersVersionSpecific_this.Writer[
[error]     |  Array[
[error]     |    de.qno.tournamentadmin.lichess.LichessInternalDataTypes.LichessDuelInterna]
[error]     |] was found.
[error]     |I found:
[error]     |
[error]     |    upickle.default.ReadWriter.join[
[error]     |
[error]     |        Array[
[error]     |          de.qno.tournamentadmin.lichess.LichessInternalDataTypes.LichessDuelInterna
[error]     |          ]
[error]     |
[error]     |    ](
[error]     |      upickle.default.ReadWriter.join[
[error]     |
[error]     |          Array[
[error]     |            de.qno.tournamentadmin.lichess.LichessInternalDataTypes.
[error]     |              LichessDuelInterna
[error]     |          ]
[error]     |
[error]     |      ](
[error]     |        upickle.default.ArrayReader[
[error]     |          de.qno.tournamentadmin.lichess.LichessInternalDataTypes.LichessDuelInterna
[error]     |          ](
[error]     |          upickle.default.ReadWriter.join[
[error]     |
[error]     |              de.qno.tournamentadmin.lichess.LichessInternalDataTypes.
[error]     |                LichessDuelInterna
[error]     |
[error]     |          ](
[error]     |            de.qno.tournamentadmin.lichess.LichessInternalDataTypes.
[error]     |              LichessDuelInterna.derived$ReadWriter,
[error]     |            upickle.default.ReadWriter.join[
[error]     |
[error]     |                de.qno.tournamentadmin.lichess.LichessInternalDataTypes.
[error]     |                  LichessDuelInterna
[error]     |
[error]     |            ](
[error]     |              de.qno.tournamentadmin.lichess.LichessInternalDataTypes.
[error]     |                LichessDuelInterna.derived$ReadWriter,
[error]     |              de.qno.tournamentadmin.lichess.LichessInternalDataTypes.
[error]     |                LichessDuelInterna.derived$ReadWriter
[error]     |            )
[error]     |          ),
[error]     |          scala.reflect.ClassTag.apply[
[error]     |
[error]     |              de.qno.tournamentadmin.lichess.LichessInternalDataTypes.
[error]     |                LichessDuelInterna
[error]     |
[error]     |          ](
[error]     |            classOf[
[error]     |              de.qno.tournamentadmin.lichess.LichessInternalDataTypes.
[error]     |                LichessDuelInterna
[error]     |            ]
[error]     |          )
[error]     |        ),
[error]     |        /* ambiguous: both method ArrayWriter in trait Writers and method join in object ReadWriter match type upickle.default.Writer[
[error]     |      Array[
[error]     |        de.qno.tournamentadmin.lichess.LichessInternalDataTypes.LichessDuelInterna]
[error]     |    ] */
[error]     |          summon[
[error]     |            upickle.default.Writer[
[error]     |              Array[
[error]     |                de.qno.tournamentadmin.lichess.LichessInternalDataTypes.
[error]     |                  LichessDuelInterna
[error]     |              ]
[error]     |            ]
[error]     |          ]
[error]     |      ),
[error]     |      upickle.default.ReadWriter.join[
[error]     |
[error]     |          Array[
[error]     |            de.qno.tournamentadmin.lichess.LichessInternalDataTypes.
[error]     |              LichessDuelInterna
[error]     |          ]
[error]     |
[error]     |      ](
[error]     |        /* ambiguous: both method ArrayReader in trait Readers and method join in object ReadWriter match type upickle.default.Reader[
[error]     |      Array[
[error]     |        de.qno.tournamentadmin.lichess.LichessInternalDataTypes.LichessDuelInterna]
[error]     |    ] */
[error]     |          summon[
[error]     |            upickle.default.Reader[
[error]     |              Array[
[error]     |                de.qno.tournamentadmin.lichess.LichessInternalDataTypes.
[error]     |                  LichessDuelInterna
[error]     |              ]
[error]     |            ]
[error]     |          ]
[error]     |        ,
[error]     |        upickle.default.ArrayWriter[
[error]     |          de.qno.tournamentadmin.lichess.LichessInternalDataTypes.LichessDuelInterna
[error]     |          ](
[error]     |          upickle.default.ReadWriter.join[
[error]     |
[error]     |              de.qno.tournamentadmin.lichess.LichessInternalDataTypes.
[error]     |                LichessDuelInterna
[error]     |
[error]     |          ](
[error]     |            upickle.default.ReadWriter.join[
[error]     |
[error]     |                de.qno.tournamentadmin.lichess.LichessInternalDataTypes.
[error]     |                  LichessDuelInterna
[error]     |
[error]     |            ](
[error]     |              de.qno.tournamentadmin.lichess.LichessInternalDataTypes.
[error]     |                LichessDuelInterna.derived$ReadWriter,
[error]     |              de.qno.tournamentadmin.lichess.LichessInternalDataTypes.
[error]     |                LichessDuelInterna.derived$ReadWriter
[error]     |            ),
[error]     |            de.qno.tournamentadmin.lichess.LichessInternalDataTypes.
[error]     |              LichessDuelInterna.derived$ReadWriter
[error]     |          )
[error]     |        )
[error]     |      )
[error]     |    )
[error]     |
[error]     |But both method ArrayWriter in trait Writers and method join in object ReadWriter match type upickle.default.Writer[
[error]     |  Array[
[error]     |    de.qno.tournamentadmin.lichess.LichessInternalDataTypes.LichessDuelInterna]
[error]     |].

问题分析

编译器在生成Array[LichessDuelInterna]的ReadWriter时,发现两种可用的构造路径:

  • 直接调用Writers trait中的ArrayWriter方法
  • 通过ReadWriter对象的join方法组合生成

Scala无法自动判定最优路径,因此抛出编译歧义错误。

补充背景

正在开发一款自动发布团队Lichess赛事预告与结果的工具,支持Lichess内部消息、X和Bluesky,后续计划扩展到Threads和Mastodon。因Lichess无官方Scala客户端库,自行实现API交互逻辑,使用uPickle进行JSON序列化与反序列化。

解决方法

方法1:显式提供数组的ReadWriter实例

手动为数组类型生成ReadWriter,避免编译器的歧义判断:

import upickle.default._

case class LichessDuelInterna(n: String, r: Int, k: Int) derives ReadWriter

// 显式定义数组的ReadWriter实例
given ReadWriter[Array[LichessDuelInterna]] = 
  ReadWriter.join(ArrayReader(ReadWriter[LichessDuelInterna]), ArrayWriter(ReadWriter[LichessDuelInterna]))

case class LichessDuels(id: String, p: Array[LichessDuelInterna]) derives ReadWriter

方法2:使用Seq替代Array

uPickle对Scala标准集合类型(如Seq)的支持更稳定,不会出现歧义问题:

case class LichessDuels(id: String, p: Seq[LichessDuelInterna]) derives ReadWriter
  
case class LichessDuelInterna(n: String, r: Int, k: Int) derives ReadWriter

如果需要和Java API交互,后续可通过.toArray或Seq.fromArray进行类型转换。

方法3:自定义派生逻辑

通过upickle的macroRW显式指定派生方式,替代derives关键字:

import upickle.default._

case class LichessDuelInterna(n: String, r: Int, k: Int)
object LichessDuelInterna:
  given ReadWriter[LichessDuelInterna] = macroRW

case class LichessDuels(id: String, p: Array[LichessDuelInterna])
object LichessDuels:
  given ReadWriter[LichessDuels] = macroRW

内容的提问来源于stack exchange,提问作者Christian H. Kuhn

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 17:12:03