官术网_书友最值得收藏!

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類型。

主站蜘蛛池模板: 屏边| 尼玛县| 炉霍县| 尉氏县| 周口市| 泰来县| 华宁县| 民和| 衢州市| 三亚市| 于田县| 清流县| 南康市| 巩义市| 景德镇市| 九龙坡区| 县级市| 台南县| 微博| 东光县| 本溪市| 东乡族自治县| 密山市| 香港 | 广昌县| 揭阳市| 改则县| 正安县| 马龙县| 石阡县| 鹿邑县| 仲巴县| 昭觉县| 齐河县| 莱阳市| 邯郸市| 邓州市| 陇南市| 东阿县| 雅安市| 灵石县|