簡體   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