// 声明了一个Int类型对象n,
// 并为它初始化为1000
let n = 1000
// 注意!
// 如果直接写:let c = Int8(n)
// 将会引发运行时异常!
// 由于1000已经超出了Int8能表示的范围。
// 所以我们这里先通过按位与操作,
// 将1000值压缩到[0, 127]之间。
let c = Int8(n & 127)
这里需要特别留意的是,高精度数据转换为低精度数据之前,必须确保高精度数据的值的范围已经在目标精度的范围内,否则在运行时转换将会引发异常。倘若不在目标精度范围内,我们可以通过按位与操作对源数值进行压缩。
此外,Swift中的每种数值类型以及布尔类型还提供了一个可供 NSNumber 类型作为输入参数的构造方法。该构造方法可以通过 NSNumber 对整数或浮点数进行封装,然后内部采取高位截断或符号位扩充的形式转换为目标数据类型。而这种数据转换与大部分主流环境下的C语言正好可以兼容。
// 声明一个Int类型常量n,
// 用1000对它初始化
let n = 1000
// 通过NSNumber进行转换,
// 其过程就类似于C语言中的类型转换。
// 这里是将Int类型直接截断高位,
// 仅保留低8位,最后取8位补码作为最终数值。
// 输出:c = -24
print("c = \(c)")
// 上述转换过程算法如下所示:
c = { () -> Int8 in
var tmp = n & 0xff
if tmp > 127 {
tmp -= 256
}
return Int8(tmp)
}()
// 将Int8类型转换为UInt16类型,
// 这里对Int8的二进制补码形式做高位符号位扩充
let a = UInt16(truncating: NSNumber(value: c))
// 输出:a = 65512
print("a = \(a)")
// 通过NSNumber也可以将一个整数转换为布尔类型对象。
// 这同样也类似于C语言中的转换过程。
var b = Bool(truncating: NSNumber(value: c))
// 上述转换其实等价于:
b = c != 0 ? true : false
print("b = \(b)")
整数与浮点数可用的计算操作符
- 整数与浮点数可用的算术计算操作符有:加法(+)、减法(-)、乘法(*)、除法(/)以及取相反数操作(-)和取正数操作符(+)。这里各位要注意的是,加法和减法操作符属于双目操作符,它需要两个操作数;而取相反数操作符和取正数操作符则都是单目操作符,它们只需要一个操作数。此外,整数类型对象还能使用求模操作(%),而浮点数则不能作为求模操作的操作数。
- 整数与浮点数还都能使用比较操作符:大于(>)、大于等于(>=)、小于(<)、小于等于(<=)、等于(==)以及不等于(!=)。比较操作符的结果类型都是布尔类型。如果比较操作符的左操作数与右操作数的比较关系成立,那么结果为真(true);否则结果为假(false)。
- 整数类型对象还能使用按位操作:按位与(&)、按位或(|)、按位异或(^)、按位取反(~)。
整数类型对象还能使用移位操作:左移(<<)、右移(>>)。这里各位要注意的是右移操作。如果右移操作的左操作数是一个带符号整数,那么使用的是扩充符号位的算术右移;如果左操作数是一个无符号整数,那么使用的是高位直接用零填充的逻辑右移。此外,必须要注意的是,移位操作的右操作数必须是一个非负整数.
var a: Int8 = -1
a >>= 7 // a的结果为-1
var b: UInt8 = 255
b >>= 7 // b的结果为1
// 因为8正好是算术左移左操作数的位宽大小,
// 因此a的值为0
a <<= 8
// 因为8正好是逻辑右移左操作数的位宽大小,
// 因此b的值为0
b >>= 8
C语言中关系操作符(即Swift中的比较操作符)的优先级比按位操作符要高,这是因为C语言中没有显式的布尔类型,一个关系操作符的结果也是一个整型值。而在Swift编程语言中就不是如此了,Swift编程语言中,移位操作符、按位操作符的优先级都比条件操作符要高。其实这种安排对于程序员而言更为自然。
let a = 1, b = 2
var result = a & b < a | b
// 输出:result = true
print("result = \(result)")
result = a << 2 > b << 1
// 输出:result = false
print("result = \(result)")
布尔类型对象可以使用逻辑操作符:并且(&&)、或者(||)以及非(!)。如果一个逻辑表达式中存在多个逻辑操作符,那么其操作优先级为:! > && > ||。
对于并且(&&)操作,如果其左操作数表达式的值为假,那么直接返回结果 false,而不会执行其右操作数的表达式。对于或者(||)操作,如果其左操作表达式的值为真,那么也不会再去计算右操作数表达式,而直接返回 true
let a = true
let b = false
var c = !b // 结果为true
c = a && b // 结果为false
c = a || b // 结果为true
/// foo1的功能为打印foo1,
/// 且返回0
func foo1() -> Int {
print("foo1")
return 0
}
/// foo2的功能为打印foo2,
/// 且返回1
func foo2() -> Int {
print("foo2")
return 1
}
// 这里当&&的左操作数表达式的值为false时就不再继续执行&&的右操作数表达式了,
// 所以只输出foo1,并且bool的值为false
var bool = foo1() > 1 && foo2() < 0
print("bool = \(bool)")
// 这里当||的左操作数表达式的值为false时,
// 还需要继续判断||的右操作数表达式的值,
// 所以这里会打印出foo1和foo2,
// 这里的bool仍然为false
bool = foo1() > 1 || foo2() < 0
print("bool = \(bool)")
// 当||的左操作数表达式的值为true时,
// 则不会再去计算||右操作数表达式。
// 所以这里只会打印出foo1,
// 这里的bool为true
bool = foo1() < 1 || foo2() > 0
print("bool = \(bool)")
// 这里用于判别&&与||操作的优先级,
// 这里先执行||左边的表达式:foo1() > 1 && foo2() < 0,
// 然后执行||右边的表达式:foo2() < 3 && foo1() < 10,
// 最后bool的值为true
bool = foo1() > 1 && foo2() < 0 || foo2() < 3 && foo1() < 10
print("bool = \(bool)")
Swift编程语言中的赋值操作符(=)以及与赋值操作相关的 +=、-=、*=、/= 等操作符与C语言的返回类型有所不同!C语言中,这些操作符表达式的返回类型为这些操作符的左操作数类型;而在Swift中则是返回 Void 类型。
溢出计算操作
如果对一个整数做一般算术计算时发生了溢出,那么程序会在运行时抛出异常。Swift中包含了允许计算时发生溢出的操作符,以允许开发者对整数做算术计算时发生结果溢出,而不引发异常。这些操作符包括:可溢出的加法(&+)、可溢出的减法(&-)以及可溢出的乘法(&*)。这些可溢出的计算操作就跟C语言的通常实现效果一样了——无论当前计算结果是多少,把高位舍去,只保留能容下当前整数对象的低位比特位,然后以补码的形式确定数值。
let a: Int8 = 120
let b: Int8 = 100
// c的加法结果为220,类型为Int8
// 对应于二进制: 1101 1100
// 其补码对应的十进制数为-36
var c = a &+ b
// 此时c的减法结果为-220,
// 对应的二进制:1 0010 0100
// 将超过8位的最高位1去除,
// 剩余的低8位是:0010 0100
// 其补码对应的十进制数为36
c = -100 &- a
// 这里c的乘法结果是12000。
// 十六进制表达为:0x2EE0
// 将高8位去除,只保留低8位,
// 得到:1110 0000,
// 其补码对应的十进制数为-32
c = a &* b
以上执行过程全都正常,不会有任何异常抛出。
网友评论