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

如何为联合类型定义类型类?解决无限递归问题

解决Scala联合类型类型类的无限递归问题

问题原因

你遇到的无限递归是因为在Foo[Value]的扩展方法实现中,模式匹配后的i: Int和s: String在当前上下文里,编译器默认会绑定Foo[Value]这个given实例来解析bar扩展方法,而非对应的Foo[Int]或Foo[String],导致每次调用都会回到Foo[Value]的bar方法,形成递归。

解决方案

方案1:调整类型类结构(推荐)

把bar定义为类型类的核心方法,扩展方法基于类型类方法实现,这样可以直接通过summon获取具体类型的实例并调用方法,彻底避免歧义:

// 重构类型类,将bar作为类型类的核心方法
trait Foo[A]:
  def bar(a: A): String

// 单独定义扩展方法,复用类型类的bar实现
extension [A](a: A)(using f: Foo[A])
  def bar: String = f.bar(a)

// 保持原有的Int和String实例不变
given Foo[Int] with
  def bar(a: Int): String = s"Int: $a"

given Foo[String] with
  def bar(a: String): String = s"String: $a"

// 联合类型定义
type Value = String | Int

// 实现联合类型的Foo实例
given Foo[Value] with
  def bar(v: Value): String = v match
    case i: Int => summon[Foo[Int]].bar(i)
    case s: String => summon[Foo[String]].bar(s)

方案2:显式指定using实例(无需修改原类型类)

如果不想改动原类型类结构,可以在调用bar时显式传入对应类型的given实例,强制编译器使用正确的类型类实现:

// 保持原类型类定义不变
trait Foo[A]:
  extension (a: A)
    def bar: String

// 原有的Int和String实例
given Foo[Int] with
  extension (a: Int)
    def bar: String = s"Int: $a"

given Foo[String] with
  extension (a: String)
    def bar: String = s"String: $a"

// 联合类型定义
type Value = String | Int

// 显式指定using实例避免递归
given Foo[Value] with
  extension (v: Value)
    def bar: String = v match
      case i: Int => i.bar(using summon[Foo[Int]])
      case s: String => s.bar(using summon[Foo[String]])

验证效果

现在调用Value类型的bar方法会正确分发到对应类型的实现:

val v1: Value = 123
val v2: Value = "hello"
println(v1.bar) // 输出 Int: 123
println(v2.bar) // 输出 String: hello

内容的提问来源于stack exchange,提问作者Todd O'Bryan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 09:52:35