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

Scala中Calendar转PublicationSchedule隐式转换栈溢出问题排查

Scala隐式转换栈溢出问题排查与解决

在Scala 2.12.19环境下,将Calendar隐式转换为PublicationSchedule时出现栈溢出异常,栈追踪显示转换方法calendarToPublicationSchedule陷入无限递归。以下是问题复现代码、对比示例及解决建议:

问题复现代码

import scala.language.implicitConversions
import java.time.{DayOfWeek, LocalDate}

object DayOfTheWeek extends Enumeration {
  type DayOfTheWeek = Value

  val Monday = Value(DayOfWeek.MONDAY.getValue())
  val Tuesday = Value(DayOfWeek.TUESDAY.getValue())
  val Wednesday = Value(DayOfWeek.WEDNESDAY.getValue())
  val Thursday = Value(DayOfWeek.THURSDAY.getValue())
  val Friday = Value(DayOfWeek.FRIDAY.getValue())
  val Saturday = Value(DayOfWeek.SATURDAY.getValue())
  val Sunday = Value(DayOfWeek.SUNDAY.getValue())

  val weekDays = List(Monday, Tuesday, Wednesday, Thursday, Friday)
  val weekEnd = List(Saturday, Sunday)
  val allDays =
    List(Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday)
}

import DayOfTheWeek._

object PublicationDateRule extends Enumeration {
  type PublicationDateRule = Value
  type PublicationDateRules = Map[DayOfTheWeek, PublicationDateRule]
  val Ignore = Value(1, "Ignore")
  val Next = Value(2, "Next")
  val Previous = Value(3, "Previous")
}

import PublicationDateRule._

object MyImplicits {
  implicit val localDateOrdering: Ordering[LocalDate] =
    Ordering.by(_.toEpochDay)
  implicit def calendarToPublicationSchedule(c: Calendar): PublicationSchedule =
    PublicationSchedule(
      c,
      c.days, // 问题根源所在
      Map(
        Monday -> Ignore,
        Tuesday -> Ignore,
        Wednesday -> Ignore,
        Thursday -> Ignore,
        Friday -> Ignore,
        Saturday -> Ignore,
        Sunday -> Ignore
      )
    )
}

import MyImplicits._

case class Calendar(
    identifier: String,
    nonWorkingDays: Seq[DayOfTheWeek],
    holidays: Seq[LocalDate]
) 

case class PublicationSchedule(
    calendar: Calendar,
    days: Seq[DayOfTheWeek],
    holidayRules: PublicationDateRules
)


val londonBankHolidays = Calendar(
  "London Bank Holidays",
  weekEnd,
  List(
    LocalDate.parse("2024-01-01"),
    LocalDate.parse("2024-03-29"),
    LocalDate.parse("2024-04-01"),
    LocalDate.parse("2024-05-05"),
    LocalDate.parse("2024-08-26"),
    LocalDate.parse("2024-12-25"),
    LocalDate.parse("2024-12-26")
  )
)

val ps: PublicationSchedule = londonBankHolidays

ps

对比正常示例

以下Inner转Outer的隐式转换可正常运行,核心区别在于转换方法中未引用不存在的字段:

import scala.language.implicitConversions

object MyImplicits {
  implicit def innerToOuter(inner: Inner): Outer =
    Outer(inner, inner.number + 1)
}

import MyImplicits._

case class Inner(number: Int)

case class Outer(inner: Inner, number: Int)

val inner = Inner(42);

val outer: Outer = inner;

outer

问题根源分析

栈溢出的核心原因是隐式转换方法中引用了Calendar类不存在的days字段:

  • Calendar类定义的字段仅为identifier、nonWorkingDays和holidays,没有days成员;
  • 当Scala编译器找不到c.days时,会尝试通过已定义的隐式转换将c(Calendar实例)转为PublicationSchedule,再访问PublicationSchedule的days字段;
  • 这导致转换方法内部反复调用自身,形成无限递归,最终触发栈溢出。

解决建议

将转换方法中的c.days替换为Calendar类存在的字段或符合业务逻辑的正确值,例如:

  • 如果需要所有日期,使用DayOfTheWeek.allDays;
  • 如果需要工作日,使用DayOfTheWeek.allDays.filterNot(c.nonWorkingDays.contains);
  • 或直接传入业务需求的Seq[DayOfTheWeek]实例。

修改后的转换方法示例:

implicit def calendarToPublicationSchedule(c: Calendar): PublicationSchedule =
  PublicationSchedule(
    c,
    DayOfTheWeek.allDays.filterNot(c.nonWorkingDays.contains), // 替换为工作日列表
    Map(
      Monday -> Ignore,
      Tuesday -> Ignore,
      Wednesday -> Ignore,
      Thursday -> Ignore,
      Friday -> Ignore,
      Saturday -> Ignore,
      Sunday -> Ignore
    )
  )

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 22:42:04