簡體   English   中英

Scala 等價於 Java 的數字

[英]Scala equivalent of Java's Number

我正在嘗試為數值域類型構建一個類型層次結構。 Year是一個Int (這是一個Number ),一個PercentageDouble ,這是一個Number ,等我需要的層次結構,以便我可以調用toInttoDouble上的值。

但是,原始數字類型的 Scala 類型層次結構除了AnyVal之外沒有共同的祖先。 這不包含我需要的to{Int, Double}函數。

我能找到的最接近的類型是Numeric[T] ,它似乎主要存在於某些編譯器技巧中。

在 Java 中,所有從Number派生的Number (包括任意精度的數字)。 如何在 Scala 中定義一個滿足數值類型對象的接口?

我目前正在用鴨子打字來破解它:

Any {
  def toInt: Int
  def toDouble: Double
}

這不僅冗長,而且會產生運行時反射成本。 有什么更好的嗎?

Numeric[T]正是您要查找的內容。 Scala 的方法是使用類型類(即類似Numeric的東西)。

代替

def foo(x: java.lang.Number) = x.doubleValue

寫其中之一

def foo[T](x: T)(implicit n: Numeric[T]) = n.toDouble(x)
def foo[T : Numeric](x: T) = implicitly[Numeric[T]].toDouble(x)

其中第二個(幾乎)只是語法糖。

數字操作

當表達式更復雜時,每次需要操作時編寫對Numeric實例的調用可能會變得笨拙。 為了減輕這種, Numeric提供的隱式轉換mkNumericOps用於擴充T與寫入的數學運算(即常見方式1 + 2 ,而不是n.plus(1,2)

為了使用這些,只需導入隱式Numeric的成員:

def foo[T](x: T)(implicit n: Numeric[T]) = {
  import n._
  x.toDouble
}

請注意,由於import的限制,隱式的縮寫語法在這里幾乎是不可取的。

類型類

這里會發生什么? 如果參數列表被標記為implicit ,編譯器將自動將所需類型的值放在那里,如果該類型的值恰好有一個標記為implicit存在於范圍內。 如果你寫

foo(1.0)

編譯器會自動將其更改為

foo(1.0)(Numeric.DoubleIsFractional)

為方法foo提供對Double操作。

這樣做的巨大優勢是您可以在他們不知道的情況下創建Numeric類型。 假設您有一個為您提供類型MyBigInt的庫。 現在假設在 Java 世界中——不幸的是——開發人員沒有讓它擴展Number 你無能為力。

在 Scala 中,你可以只寫

implicit object MyBigIntIsNumeric extends Numeric[MyBigInt] {
   def compare(x: MyBigInt, y: MyBigInt) = ...
   // ...
}

並且您使用Numeric所有代碼現在都可以與MyBigInt一起MyBigInt您不必更改庫 因此Numeric甚至可以是您項目的私有數據,並且這種模式仍然有效。

@gzm0 的答案是靜態解決方案,必須在編譯時檢查類型,我給出了一個動態解決方案,在運行時轉換類型,

def toDoubleDynamic(x: Any) = x match { case s: String => s.toDouble case jn: java.lang.Number => jn.doubleValue() case _ => throw new ClassCastException("cannot cast to double") }

它使用 case match 在運行時選擇正確的類型。

暫無
暫無

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

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