簡體   English   中英

在某些特征可以實現也可以不相同的特征中實現最終定義

[英]Implement a final def within some trait where type parameters may or may not be the same

在我的問題之前進行一些設置:

/* roughly equivalent to a union type */
sealed trait NewType

object NewType {
  final case class Boolean(record: Boolean) extends NewType
  final case class Long(record: Long) extends NewType
  final case class String(record: String) extends NewType
}


/* Try to convert a record of type T to a NewType */
sealed trait NewTypeConverter[T] { def apply(record: T): Option[NewType] }

object NewTypeConverter {
  trait BooleanConverter[T] extends NewTypeConverter[T] {
    override def apply(record: T): Option[NewType.Boolean]
  }

  trait LongConverter[T] extends NewTypeConverter[T] {
    override def apply(record: T): Option[NewType.Long]
  }

  trait StringConverter[T] extends NewTypeConverter[T] {
    override def apply(record: T): Option[NewType.String]
  }
}

我想定義一個特征Data ,如下所示:

trait Data[T] {
  def name: String
  def converter: NewTypeConverter[_]
  final def value(record: T): Option[NewType] = ??? // calls converter
}

如何實現此final def value(record: T): Option[NewType]

注意事項:

  • converterapply方法的返回類型必須與value相同。 因此,如果您碰巧具有BooleanConverter ,則value必須返回Option[NewValue.Boolean]
  • Data特征的輸入類型T不必與converter的輸入類型_相同。 如果它們碰巧是同一類型,則實現可能只是final def value(record: T): Option[NewType] = converter(record) 輸入類型不同時,情況更棘手。 假設Data的輸入類型是String ,而converter的輸入類型是Long 如何處理?

看起來您90%的人都通過實現Type Class模式來實現,所以我將嘗試通過完成它來解決您的問題。 這是一篇不錯的文章。 簡而言之,您錯過的是一個簽名,該簽名指出,如果可以在隱式作用域中找到轉換器的一個(只有一個)實現,請使用它來運行轉換(或特征定義的任何其他操作)。

簽名如下:

final def value(record: T)(implicit c: NewTypeConverter[T]): Option[NewType]

給出這樣嚴格的簽名也使實現非常簡單:

final def value(record: T)(implicit c: NewTypeConverter[T]): Option[NewType] =
  c(record) // literally only applies `c`, the converter

現在,每當您的轉換器實例在隱式范圍內時,例如以下內容:

implicit val converter: NewTypeConverter[Boolean] =
  new StringConverter[Boolean] {
    override def apply(record: Boolean): Option[NewType.String] =
      if (record) Some(NewType.String("TRUE"))
      else Some(NewType.String("FALSE"))
 }

您可以實例化您的trait (在示例中進行了簡化):

trait Data[T] {
  def name: String
  final def value(record: T)(implicit c: NewTypeConverter[T]): Option[NewType] =
    c(record)
}

final case class BooleanData(name: String) extends Data[Boolean]

val bool = BooleanData(name = "foo")

並使用它:

println(bool.value(true)) // prints Some(String(TRUE))
println(bool.value(false)) // prints Some(String(FALSE))

如果您嘗試從無法訪問隱式實例的位置調用value方法,則會收到錯誤消息:

錯誤:找不到參數轉換器的隱式值:NewTypeConverter [Boolean]

獎金

通過隱式提供對象已知功能的證據非常普遍,以至於Scala有一些語法糖,如果您需要提供此類證據(例如,您有一個調用您的value方法的方法),則可以使用它直接使用它。 它表示如下,與:通用型之后:

def methodThatCallsValue[T: Data](convertee: T): Option[NewType] =
  data.value(convertee)

它稱為上下文綁定 ,它等效於以下內容(在示例中已明確完成):

def methodThatCallsValue(convertee: T)(implicit $ev: Data[T]): Option[NewType] =
  data.value(convertee)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM