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

Scala中元组列表尾递归归并排序@tailrec不生效问题排查

解决Scala元组列表归并排序中@tailrec注解不生效的问题

问题原因

你遇到的报错看似矛盾——明明给merge方法加了final注解,却仍被提示“method merge is neither private nor final”。这是因为Scala的尾递归优化对方法的确定性要求极高:仅仅标记final还不够,若方法是默认的公共可见性,编译器无法完全排除外部代码通过继承等方式干扰优化的可能,因此会拒绝进行尾递归优化。

解决方案

有两种方式可以满足编译器的尾递归优化要求:

方案1:将merge设为私有方法

私有方法默认无法被重写,编译器可以安全地执行尾递归优化:

def mergeSort(lst: List[(Int, Int)]): List[(Int, Int)] = {
  if (lst.length <= 1) lst
  else {
    val mid = lst.length / 2
    val left = mergeSort(lst.take(mid))
    val right = mergeSort(lst.drop(mid))
    merge(left, right)
  }
}

@tailrec
private def merge(left: List[(Int, Int)], right: List[(Int, Int)], acc: List[(Int, Int)] = Nil): List[(Int, Int)] = (left, right) match {
  case (Nil, _) => acc.reverse ::: right
  case (_, Nil) => acc.reverse ::: left
  case (h1 :: t1, h2 :: t2) =>
    if (h1._1 <= h2._1) merge(t1, right, h1 :: acc)
    else merge(left, t2, h2 :: acc)
}

方案2:使用private[this]限制方法作用域

如果需要保留方法的内部可见性(比如在同一个类的其他方法中调用),可以用private[this]标记,将方法限制为仅当前实例可调用,彻底消除被重写的可能:

@tailrec
private[this] final def merge(left: List[(Int, Int)], right: List[(Int, Int)], acc: List[(Int, Int)] = Nil): List[(Int, Int)] = (left, right) match {
  case (Nil, _) => acc.reverse ::: right
  case (_, Nil) => acc.reverse ::: left
  case (h1 :: t1, h2 :: t2) =>
    if (h1._1 <= h2._1) merge(t1, right, h1 :: acc)
    else merge(left, t2, h2 :: acc)
}

补充说明

你的mergeSort方法本身不是尾递归(递归调用后还需要执行merge操作),因此无需添加@tailrec注解,这部分逻辑是正确的。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 15:14:55