Scala之Numbers
一、前言
前面已經學習了Scala中的String,接着學習Scala的Numbers。
二、Numbers
在Scala中,所有的數字類型,如Byte,Char,Double,Float,Int,Long,Short都是對象,這七種數字類型繼承AnyVal特質,這七種數字類型與其在Java中有相同的范圍,而Unit和Boolean則被認為是非數字值類型,Boolean有false和true兩個值,你可以獲取到各個數字類型的最值。
復雜的數字和日期
如果需要更強大的數類,可以使用spire,scalalab。
如果需要更強大的日期類,可以使用Joda Time,nscala-time。
2.1 從字符串中解析數字
1. 問題
你想要將字符串類型轉化為數字類型。
2. 解決方案
使用String的to*方法即可將String轉化為相應的數字。
當無法進行轉化時,to*方法可能會拋出NumberFormatException異常。
可以直接使用字符串來創建BigInt和BigDecimal實例(也可能會拋出異常)
處理基和基數
如果在計算時不以10為基(十進制)進行計算,而要使用其他進制,此時Int類的toInt方法不允許傳入基和基數,此時需要使用parseInt方法,parseInt可將字符串轉化為在指定進制下的值
也可以使用隱式轉化來完成上述的功能
3. 討論
由於在Scala中沒有受檢查異常,因此你不需要在方法中聲明throws NumberFormatException。但是為了使調用者明白該方法可能會拋出異常,你可以使用throws注解
@throws(classOf[NumberFormatException]) def toInt(s: String) = s.toInt
更通常而言,在Scala中使用Option/None/Some進行模式匹配來處理
def toInt(s: String):Option[Int] = { try { Some(s.toInt) } catch { case e: NumberFormatException => None } }
此時你就可以使用不同的方法來調用toInt方法
println(toInt("1").getOrElse(0)) // 1 println(toInt("a").getOrElse(0)) // 0
另外一種使用方法就是使用匹配表達式
toInt(aString) match { case Some(n) => println(n) case None => println("Boom! That wasn't a number.") }
也可以使用如下直接提取出值
val result = toInt(aString) match { case Some(x) => x case None => 0 }
2.2 數字類型間的轉化
1. 問題描述
你想要從一種數字類型轉化為另一種數字類型,如從Int到Double。
2. 解決方案
不同於Java使用cast方法,Scala中可以直接使用數字類型提供的to*方法。
3. 討論
在Java中,需要強制轉化來將double類型轉化為int類型
int a = (int) 100.00;
但是在Scala中,使用to*方法即可完成上述轉化,如果你想要避免轉化錯誤,你可以使用isValid方法來測試是否可以轉化
2.3 重寫默認類型
1. 問題描述
當你給變量賦值時,Scala會自動給變量賦予相應的類型,當你創建數字字段時,你需要重寫默認的類型。
2. 解決方案
如果你將1賦值給變量a,那么a默認為Int類型
下面例子重寫了默認類型
另一種方法是用類型注釋變量
也可以在等號左邊進行定義
你也可以在數字前面添加0x或0X來創建十六進制整形
3. 討論
當創建對象實例時,應該注意如下語法結構
var [name]:[Type] = [initial value]
在初始化數字類型的var字段時,可以使用占位符,其值默認為0,占位符僅僅只在類定義時有效,其他時候則不行,如在方法內部定義不起作用
class Foo { var a: Short = 0 // 定義初始值 var b: Short = _ // 默認為0 }
但在方法中,可以使用如下方法
var name = null.asInstanceOf[String]
當然更好的辦法是使用Option/None/Some模式匹配,這樣可以避免空值
2.4 替換++、--
1. 問題描述
在其他語言中,你可以使用++、--來增1、減1,然而,在Scala中沒有++、--操作符
2. 解決方案
由於val類型變量是不可變的,所以不能進行加法或減法的操作,但是var類型是可變,可以使用+=、-=方法來進行加法或減法
同理,也可以使用*=、/=方法進行乘法、除法操作
值得注意的是+=、-=、*=、/=都不是操作符,而是方法,他們是var型Int變量上實現的方法。
3. 討論
在其他數字類型上也可以使用+=、-=、*=、/=方法
2.5 比較浮點數
1. 問題描述
你需要比較兩個浮點數,但在其他一些編程語言中,它們應該是相等的兩個浮點數
2. 解決方案
在Java和許多其他語言,你可以通過創建一個指定比較精度的方法來決這個問題,下面是約等於方法
def ~=(x: Double, y: Double, precision: Double) = { if ((x - y).abs < precision) true else false }
3. 討論
當進行浮點數計算時,0.1 + 0.1等於0.2,但是0.1 + 0.2不等於0.3
這種細小的錯誤使得比較兩個浮點數成為真正的問題。
因此,你需要自定義比較精度的函數來比較兩個浮點數是否相等,你可以定義隱式轉化,然后在需要是引入即可。或者將方法放在object對象中,這樣可以直接調用
object MathUtils { def ~=(x: Double, y: Double, precision: Double) = { if ((x - y).abs < precision) true else false }
然后直接通過MathUtils調用~=方法進行比較
println(MathUtils.~=(a, b, 0.000001))
2.6 處理大數
1. 問題描述
你正在編寫需要使用非常大的整數或十進制數的應用程序
2. 解決方案
你可以使用BigInt或BigDecimal類
不同於其在Java的對應類,這些類支持所有你使用數字類型的操作符
你也可以把它們轉化為其他數字類型
為了避免錯誤,也可以在轉化之前進行測試
3. 討論
雖然Scala中的BigInt和BigDecimal是由Java中的BigInt和BigDecimal支持的,但是Scala中的類使用更為簡便,並且它們是可變的,可以像其他數字類型一樣操作。
2.7 生成隨機數
1. 問題描述
你需要創建隨機數,如測試應用程序、執行模擬以及許多其他情況
2. 解決方案
使用scala.util.Random來創建隨機數
你可以指定隨機生成數字的最大值
上述示例將會生成[0-99]之間的數字,你也可以生成隨機Float(0.0到1.0之間的浮點數)
也可以生成隨機Double(0.0到1.0之間的浮點數)
你也可以在創建Random時指定seed值,也可以之后調用setSeed方法進行設置
3. 討論
Random類可以應對所有通常的使用,包括生成數字、設置最大值、設置seed值,也可以生成隨機字符
Scala可以生成一段隨機長度的數字,在測試時非常有用
也可以生成隨機長度的浮點數
2.8 創建數字范圍,列表或數組
1. 問題描述
你需要創建一個數字范圍、列表或數組,如for循環或用於測試目的
2. 解決方案
使用Int類的方法來創建一個數字Range
也可以自定義間距
3. 討論
在Scala中可以很輕易的創建數字范圍,並且可以很輕易的將其轉化為列表或者數組類型
更好的方式如下
2.9 格式化數字和貨幣
1. 問題描述
你想要格式化數字和貨幣來控制小數點和逗號,特別是用於打印輸出。
2. 解決方案
對於簡單的數字格式化,可以采用前篇博文提到的f字符串插值
添加逗號的一種簡單方法是調用java.text.NumberFormat類的getIntegerInstance方法
在使用getIntegerInstance方法的時候可以指定地區
在處理浮點數時可以使用getInstance方法
對於貨幣格式,可以使用getCurrencyInstance方法
下面方法可以處理國際化貨幣
3. 討論
主要討論了使用Java的相關類來格式化數字和貨幣,也可以使用BigDecimal來處理貨幣的格式問題。
三、總結