繁体   English   中英

如何避免在具有家族多态性的 Scala 中调用 asInstanceOf

[英]How to avoid calling asInstanceOf in Scala with family polymorphism

按照设计,我们确定我们有一个HourlyDateFormat实例

在这种情况下如何避免调用 asInstanceOf (即如何帮助编译器推断类型)?

  sealed trait StorageLayout extends Product with Serializable
  case object Hourly         extends StorageLayout
  case object Daily          extends StorageLayout

  sealed trait DateFormat[S <: StorageLayout]

  sealed abstract class HourlyDateFormat extends DateFormat[Hourly.type] {
    def format(localDate: LocalDate): String         = ???
    def format(localDateTime: LocalDateTime): String = ???
  }

  sealed abstract class DailyDateFormat extends DateFormat[Daily.type] {
    def format(localDate: LocalDate): String = ???
  }

  class Log[S <: StorageLayout](storageLayout: S, dateFormat: DateFormat[S]) {
    def getPath(date: LocalDate): String =
      dateFormat match {
        case hdf: HourlyDateFormat => hdf.format(date)
        case ddf: DailyDateFormat  => ddf.format(date)
      }
    @SuppressWarnings(Array("org.wartremover.warts.AsInstanceOf"))
    def getPath(date: LocalDateTime)(implicit ev: S =:= Hourly.type): String = {
      assert(ev == ev)
      dateFormat.asInstanceOf[HourlyDateFormat].format(date)
    }
  }

尝试再添加一个隐式参数

def getPath(date: LocalDateTime)(implicit ev: S =:= Hourly.type, ev1: DateFormat[S] =:= HourlyDateFormat): String = {
  //assert(ev == ev)
  dateFormat.format(date)
}

断言看起来很奇怪: assert(ev == ev)

要不就

def getPath(date: LocalDateTime)(implicit ev1: DateFormat[S] =:= HourlyDateFormat): String

固定版本(我增加了一个类型参数,它现在类似于第一个@user的版本)

class Log[S <: StorageLayout, D <: DateFormat[S]](storageLayout: S, dateFormat: D) {
  def getPath(date: LocalDate): String =
    dateFormat match {
      case hdf: HourlyDateFormat => hdf.format(date)
      case ddf: DailyDateFormat  => ddf.format(date)
    }
  def getPath(date: LocalDateTime)(implicit
                                   ev: S =:= Hourly.type,
                                   ev1: D <:< HourlyDateFormat,
  ): String = {
    dateFormat.format(date)
  }
}

val log = new Log(Hourly, new HourlyDateFormat(){})
print(log.getPath(LocalDateTime.now()))

一般来说,这样的事情是一种典型的类型,所以我会这样做:

trait DailyFormatter[S] {
  def formatDate(localDate: LocalDate): String
}
trait HourlyFormatter[S] {
  def formatDateTime(localDateTime: LocalDateTime): String
}

implicit val dailyFormats: DailyFormatter[Daily]
implicit val hourFormats: DailyFormatter[Hourly] with HourlyFormatter[Hourly]

class Log[S <: StorageLayout](storageLayout: S, dateFormat: DateFormat[S]) {

  def getPath(date: LocalDate)(implicit formater: DailyFormatter[S]): String =
    formater.formatDate(date)

  def getPath(date: LocalDateTime)(implicit formater: HourlyFormatter[S]): String =
    formater.formatDateTime(date)
}

它的优点是您不必知道类型HourlyDateFormatDailyDateFormat的存在即可使其工作。

快速修复将是这样的:

class Log[S <: StorageLayout, D <: DateFormat[S]](storageLayout: S, dateFormat: D) {
  def getPath(date: LocalDateTime)(implicit ev: D <:< HourlyDateFormat): String =
    dateFormat.format(date)
}

但是,我认为您的设计方式不正确。 为每种类型的格式设置一个单独的特征可能会更好。 这使其更具可扩展性,因为您不需要在匹配表达式中为每个不同的 class 添加大小写,因此在运行时会自动选择正确的方法。 你仍然必须使用那些我不喜欢的证据参数,但对我来说它仍然感觉更干净。

编辑:我已经更新了代码,以便所有内容都扩展FormatLocalDate并且您只需要getPath(LocalDateTime)的证据参数

sealed trait FormatLocalDate[S <: StorageLayout] {
  def format(localDate: LocalDate): String
}
sealed trait FormatLocalDateTime[S <: StorageLayout] extends FormatLocalDate[S] {
  def format(localDate: LocalDateTime): String
}

sealed abstract class HourlyDateFormat extends FormatLocalDateTime[Hourly.type] {
  def format(localDate: LocalDate): String = ???
  def format(localDateTime: LocalDateTime): String = ???
}
sealed abstract class DailyDateFormat extends FormatLocalDate[Daily.type] {
  def format(localDate: LocalDate): String = ???
}

class Log[S <: StorageLayout, D <: FormatLocalDate[S]](storageLayout: S, dateFormat: D) {
  def getPath(date: LocalDate): String =
    dateFormat.format(date)

  def getPath(date: LocalDateTime)(implicit ev: D <:< FormatLocalDateTime[S]): String =
    dateFormat.format(date)
}

斯卡斯蒂

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM