對于“雙重定義”問題,我有幾個解決方案,但我不知道他們在解決型別擦除問題方面真正做了什么。
我也會給出一些一般性的背景資訊,因為我可能一開始就錯誤地處理了這個問題,但最終有助于理解 DummyImplicits 和在這種情況下的名稱引數就足夠了。
語境
我正在為深度嵌套的 JSON 替換決議器,其中幾乎每個值都是可選的,并且幾乎所有資料(包括 Int、Double 等)都存盤為字串。捕獲決議值的類采用這種通用形式(目前)。
case class Field1(subfield1: Option[String], subfield2: Option[String]) {
def sf1Converted: Option[Int] =
Try { subfield1.get.toInt }.filter(i => lb <= i && i <= ub).toOption
def sf2Converted: Option[Double] =
Try { subfield2.get.toDouble }.filter(d => lb <= d && d <= ub).toOption
}
這個功能,但是......它非常慢并且需要不真實的記憶體量。我的猜測是將字串轉換為數字資料會大大減少記憶體,并可能以犧牲加載時間為代價加快資料的使用。
所以我想我會做類似的事情......
/** type signature w/ numeric args instead of Strings */
case class Field1(subfield1: Option[Int], subfield2: Option[Double])
object Field1 {
/** the apply method I need for this class */
def apply(subfield1: Option[String], subfield2: Option[String]): Field1 =
new Field1(
Try { subfield1.get.toInt }.filter(i => lb <= i && i <= ub).toOption,
Try { subfield2.get.toDouble }.filter(d => lb <= d && d <= ub).toOption)
/** one more to generalize the question a bit more */
def apply(subfield1: Option[Int], subfield2: Option[Int]): Field1 =
new Field1(subfield1, Try { subfield2.get.toDouble }.filter(d => lb <= d && d <= ub).toOption)
}
這顯然會引發一些error: double definition ... have the same type after erasure錯誤。所以我找到了兩種解決方案......但我無法弄清楚其中任何一個實際上在做什么,以及我可能會在其中一個或另一個遇到什么問題。
選項 1在每個應用方法中使一個(不同的)arg 成為一個別名引數
object Field1 {
def apply(subfield1: => Option[String], subfield2: Option[String]): Field1 = ???
def apply(subfield1: Option[Int], subfield2: => Option[Int]): Field1 = ???
}
選項 2虛擬隱式
object Field1 {
def apply(subfield1: Option[String], subfield2: Option[String])(implicit i: DummyImplicit): Field1 = ???
def apply(subfield1: Option[Int], subfield2: Option[Int])(implicit i: DummyImplicit, i2: DummyImplicit): Field1 = ???
}
問題
這兩個都可以編譯,但我不明白為什么任何一個都可以解決型別擦除問題。
我認為按名稱引數僅在使用時進行評估,并在每次使用時進行評估。我不明白為什么這會解決型別擦除問題。
這里有一個很好的虛擬隱式演示,但是當它觸及問題的核心時,它只是說“每個呼叫都被賦予了正確消除呼叫歧義所需的隱式引數”。虛擬值如何做到這一點?
檔案只是說“一種總是有隱含值的型別”。
可能是一個糟糕的問題,因為我知道如何讓它發揮作用,但我完全不知道為什么任何一個選項都有效。任何幫助表示贊賞。
uj5u.com熱心網友回復:
編譯代碼的相關部分option-1看起來像
def apply(subfield1: Function0, subfield2: Option): Field1 = scala.Predef.???();
def apply(subfield1: Option, subfield2: Function0): Field1 = scala.Predef.???();
如您所見,按名稱引數轉換為Function0,因此可以重用名稱。
因為option-2隱式柯里化引數被添加為函式的額外引數,因此可以使用相同的名稱。
def apply(subfield1: Option, subfield2: Option, i: DummyImplicit): Field1 = scala.Predef.???();
def apply(subfield1: Option, subfield2: Option, i: DummyImplicit, i2: DummyImplicit): Field1 = scala.Predef.???();
您還可以看到確實發生了型別擦除。
編輯 -TypeTag用于克服型別擦除
def apply[T: TypeTag](subfield1: => Option[T], subfield2: Option[T]): Field1 =
typeOf[T] match {
case tpe if tpe =:= typeOf[String] => new Field1(subfield1.asInstanceOf[Option[String]], subfield2.asInstanceOf[Option[String]])
case tpe if tpe =:= typeOf[Int] => ???
case _ => new Field1(subfield1.map(_.toString), subfield2.map(_.toString))
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/412159.html
標籤:
