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
相关产品推荐
相关产品推荐

