3.1.5 避免算術運算中的類型錯誤
在對倉頡數值類型的數據進行算術運算時,關于數據類型,有以下5點需要注意。
1.算術操作符對操作數類型的要求
對于一元算術操作符“-(負號)”,倉頡對其操作數的類型沒有要求,只要其操作數為數值類型即可。
對于以下算術表達式:
操作數A 二元算術操作符 操作數B
如果式中的二元算術操作符不是“**”,那么倉頡要求操作數A和操作數B必須是相同的數值類型,否則會引發編譯錯誤。
注意
“%”要求操作數A和操作數B必須是相同的整數類型。
舉例如下:
main() { let intA: Int8 = 8 let intB: Int16 = 10 println(intA * 4i8) // Int8類型和Int8類型的運算 println(intB + 4i8) // 編譯錯誤:無法對Int16和Int8類型使用二元操作符“+” }
如果式中的二元算術操作符是“**”,那么操作數A和操作數B的類型必須符合表3-5中所示的3種情況中的一種,否則會引發編譯錯誤。
表3-5 乘方運算的操作數類型

舉例如下:
main() { let intC: Int64 = 3 println(intC ** 2u64) // 操作數A為Int64類型,操作數B為UInt64類型 println(intC ** 2i64) // 編譯錯誤:無法對Int64和Int64類型使用二元操作符“**” }
提示
以上算術操作符對操作數類型的要求,均是在沒有操作符重載的前提下。關于操作符重載的相關知識參見第10章。
2.算術運算結果的數據類型
對于以下算術表達式:
-操作數A
以及以下算術表達式:
操作數A 二元算術操作符 操作數B
運算結果的數據類型均與操作數A保持一致。假設有兩個Int64類型的變量x和y,以下表達式的運算結果也是Int64類型:
-x x + y x * y x ** 2u64
在進行算術運算時,必須要注意各種數值類型的表示范圍,避免溢出錯誤。舉例如下:
3i8 + 125i8 // 溢出
在以上算術表達式中,Int8類型的3加上Int8類型的125,其結果應該為128,但是由于Int8類型的表示范圍為-128~127,因此結果溢出了。
3.數值類型字面量和變量的類型推斷
前面介紹過,在沒有類型上下文的情況下,整數類型字面量會被推斷為Int64類型,浮點類型字面量會被推斷為Float64類型。舉例如下:
println(3) // 字面量3被推斷為Int64類型 println(9.5) // 字面量9.5被推斷為Float64類型
如果有類型上下文,那么編譯器會自動根據類型上下文來推斷數值類型字面量的類型。舉例如下:
main() { let x: Float32 = 9.98 let y = x + 1.5 }
在這段代碼中,x是Float32類型,因此字面量9.98被推斷為Float32類型。在表達式x + 1.5中,由于加法運算要求兩個操作數的類型是一致的,而x為Float32類型,因此字面量1.5也被推斷為Float32類型。
對于缺省了數據類型的變量聲明,編譯器也會自動推斷變量的數據類型。例如,在上面的代碼中,變量y在聲明時缺省了數據類型,而其初始值x + 1.5的類型為Float32,因此y將被推斷為Float32類型。再舉一個例子:
let z = 0.99
在以上代碼中,由于缺少類型上下文,字面量0.99將被推斷為Float64類型,因此根據初始值的類型,在聲明時缺省了數據類型的變量z將會被推斷為Float64類型。
4.數值類型的類型轉換
倉頡對算術運算的操作數類型的要求十分嚴格,除“**”運算外,不同類型的操作數之間不能進行算術運算。
如果在某些情況下確實需要對不同類型的操作數進行運算,可以考慮對操作數的類型進行轉換。舉例如下:
main() { var mile: Int64 = 3 // 表示英里 var kilometer: Float64 // 表示公里 kilometer = 1.609344 * mile // 編譯錯誤 }
以上示例程序的作用是將英里換算成公里(1英里 = 1.609344公里)。由于mile和kilometer的類型不一致,因此不能直接進行乘法運算。此時,可以將表示英里的變量值轉換為Float64類型,再進行乘法運算。
倉頡不支持不同類型之間的隱式轉換,類型轉換必須顯式地進行。倉頡支持使用以下方式得到一個值為e的T類型的實例。
T(e)
其中,T可以是各種數值類型,如Int8、Int16、Float32等,e可以是一個數值類型的表達式。
提示
當我們說e是T類型的實例時,表示e是一個T類型的值。
舉例如下:
Int64(9i8) // 結果為Int64類型的9 Float32(200u16) // 結果為Float32類型的200.0
回到換算英里和公里的例子,我們可以使用如下代碼計算出英里對應的公里數:
kilometer = 1.609344 * Float64(mile)
在各種數值類型之間進行類型轉換時,需要遵循一定的轉換規則。
首先,在整數類型之間進行轉換時,要確保待轉換的整數必須要在目標整數類型的表示范圍之內。舉例如下:
Int64(200u8) // 將UInt8類型的200轉換為Int64類型,結果為Int64類型的200 Int8(200) // 將Int64類型的200轉換為Int8類型,溢出錯誤
然后,在浮點類型之間轉換時也需要注意不同浮點類型的表示范圍,如果是精度高的浮點類型向精度低的浮點類型轉換,將會出現精度損失。舉例如下:
main() { let x: Float64 = 987.654321 let y = Float16(x) println(x) // 輸出:987.654321 println(y) // 輸出:987.500000,損失了精度 }
最后,在整數類型和浮點類型相互轉換時,要確保待轉換的類型必須要在目標類型的表示范圍之內。另外,如果是浮點類型轉換為整數類型,那么浮點數的小數部分會被直接截斷,只保留整數部分。舉例如下:
Float64(2023) // 整數類型向浮點類型轉換,結果為2023.0 Int16(7.9) // 浮點類型向整數類型轉換,結果為7
5.建議使用的數值類型
對整數類型來說,Int64類型的表示范圍最大,不容易引發溢出錯誤。另外,在沒有類型上下文的情況下,Int64類型是倉頡默認的整數類型,而使用默認的類型可以避免在運算中進行不必要的類型轉換。因此,在Int64類型適合的情況下,建議首選Int64類型。
對浮點類型來說,除了與整數類型相同的原因,由于浮點類型在存儲和運算時都會產生一定的誤差,因此精度高的浮點類型優于精度低的浮點類型。在多種浮點類型都適合的情況下,建議首選Float64類型。
- Mastering Visual Studio 2017
- CMDB分步構建指南
- 從0到1:HTML+CSS快速上手
- Android 7編程入門經典:使用Android Studio 2(第4版)
- 微信公眾平臺開發:從零基礎到ThinkPHP5高性能框架實踐
- Expert Android Programming
- Expert Data Visualization
- Visual C++開發入行真功夫
- Unity 2D Game Development Cookbook
- 區塊鏈技術與應用
- SQL Server 2008 R2數據庫技術及應用(第3版)
- 程序員必會的40種算法
- Data Manipulation with R(Second Edition)
- 優化驅動的設計方法
- INSTANT EaselJS Starter