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时,发现两种可用的构造路径:
- 直接调用
Writerstrait中的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
相关产品推荐
相关产品推荐

