类型安全和类型推断(Type Safety and Type Inference)
- Swift是一个类型安全的语言,所以会在编译的时候会检查类型不匹配的错误。这么做可以尽可能早的在开发过程中发现错误。
- 类型检查帮助避免在不同类型的值的错误。虽然这样,但也不意味着必须把每个变量(常量)的类型写出来。因为Swift使用类型推断来给出合适的类型。
let meaningOfLife = 42
//meaningOfLife is inferred to be of type Int
当不声明一个浮点型时,默认是Double类型。
let pi = 3.14159
//pi is inferred to be of type Double
let anotherPi = 3 + 0.14159
//anotherPi is also inferred to be of type Double
数字型的字面值(Numeric Literals)
- 整型的字面可以这么写:
- 十进制:不需要前缀
- 二进制:前缀为"0b"
- 八进制:前缀为"0o"
- 十六进制:前缀为"0x"
以下这些的值都是17
let decimalInteger = 17
let binaryInteger = 0b10001
let octalInteger = 0o21
let hexadecimalInteger = 0x11
-
浮点型的字面可以为十进制(没有前缀),也可以为十六进制(前缀为"0x")。十进制数用大写或者小写的e表示指数,十六进制数用大写或小写的p表示指数。
十进制:- 1.25e2 means 1.25 x 10^2, or 125.0.
- 1.25e-2 means 1.25 x 10^(-2), or 0.0125.
十六进制:
- 0xFp2 means 15 x 2^2, or 60.0.
- 0xFp-2 means 15 x 2^(-2), or 3.75.
下面这些浮点型的值都是12.1875
let decimalDouble = 12.1875
let exponentDouble = 1.21875e1
let hexadecimalDouble = 0xC.3p0
numeric literals为了更好的阅读代码可以包含额外的格式,整型和浮点型都可以使用前缀"0"和下划线"_"
let paddedDouble = 000123.456
let oneMillion = 1_000_000
let justOverOneMillion = 1_000_000.000_000_1
数值类型的转换(Numeric Type Conversion)#
- 整型的转换(Integer Conversion)
当然,整形的存储是不能超过类型的范围的,那UInt8(0255)和Int8(-128127)为例:
let cannotBeNegative: UInt8 = -1
//UInt8 cannot store negative numbers, and so this will report an error.
let tooBig: Int8 = Int8.max + 1
//Int8 cannot store a number larger than its maximum value,
//and so this will also report an error
当两种数值不是一个类型的时候是不能进行运算的,哪怕他们都是“整型”:
let twoThousand: UInt16 = 2_000
let one: UInt8 = 1
let towThousandAndOne = twoThousand + UInt16(one)
//swift的强制转换和OC是不同的,swift是将类型放在括号外面,而将变量(常量)放在括号里面。
- 整型和浮点型之间的相互转换(Integer and Floating-Point Conversion)
在整型和浮点型之间转换一定要明确:
let three = 3
let pointOneFourOneFiveNine = 0.141459
let pi = Double(three) + pointOneFourOneFiveNine
// pi equals 3.14159, and is inferred to be of type Double
类型的别称(Type Aliases)
类型的重命名用到的是"typealias"关键字。
typealias AudioSample = UInt16
//correct
let max: AudioSample = AudioSample.max
//wrong
let max: AudioSample = UInt16.max
布尔型(Boolean)
Swift中的布尔型与C语言和OC都不一样,为"Bool",而其值和C语言是一直的,分别为"true"和"false"。
因为type safety的缘故,下面的代码是错误的
let i = 1
if i {
//this example will not compile, and will repot an error
}
所以,这段代码应该这么写:
let i = 1
if i == 1 {
//this example will compile successfully
}
因为"i == 1"的返回值是Bool,所以这段代码可以执行。
元组(Tuples)
元组就是一组多个值合成为一个单一的值,而这一组的多个值并不是一定要相同的类型。
🌰:
let http404Error = (404, "Not Found")
//http404Error is of type (Int, String)
你可以在创建一个元组的时候任意的排序类型。
你也可以在定义一个元组的时候,将类型分离,🌰:
let (statusCode, statusMessage) = http404Error
print("The status code is \(statusCode)")
//Prints "The status code is 404"
如果你只需要为元组中的某个元素命名是,其他的可以用下划线(_)代替:
let (justTheStatusCode, _) = http404Error
print("The status code is \(justTheStatusCode)")
// Prints "The status code is 404"
你也可以通过访问元组的索引值来访问相应的元素:
print("The status code is \(http200Status.statusCode)")
// Prints "The status code is 200"
print("The status message is \(http200Status.description)")
// Prints "The status message is OK"
在定义一个元组的时候,就可以为每个元素命名,这样就可以直接通过元素名称来访问:
let http200Status = (statusCode: 200, description: "OK")
print("The status code is \(http200Status.statusCode)")
// Prints "The status code is 200"
print("The status message is \(http200Status.description)")
// Prints "The status message is OK"
可选变量(Optionals)#
在C语言和OC中是没有optionals的概念的,但在OC中有一个类似的类型就是NSNil。Optionals通俗点讲,就是这个值可能存在,也可能不存在。举个🌰:
let possibleNumber = "123"
let convertedNumber = Int(possibleNumber)
// convertedNumber is inferred to be of type "Int?", or "optional Int"
- nil
在声明一个变量的时候可以分配一个特殊的值——nil:
var serverResponseCode: Int? = 404
// serverResponseCode contains an actual Int value of 404
serverResponseCode = nil
// serverResponseCode now contains no value
在声明一个可选变量的时候不赋给初始值,默认为nil(数值类型的值同样为nil)。
- 可选绑定(Optional Binding)
可选绑定,如果一个可选变量的值不为nil,则将值赋给另外一个变量(常量)。可选绑定可以用在if和while的判断条件中。🌰:
if let actualNumber = Int(possibleNumber) {
print("\"\(possibleNumber)\" has an integer value of \(actualNumber)")
} else {
print("\"\(possibleNumber)\" could not be converted to an integer")
}
// Prints ""123" has an integer value of 123"
你可以在一个if判断条件中包含多个可选绑定和"where"子句来进行判断,如果其中有任意一个可选绑定为空(nil),或者"where"的返回值为"false",整个可选绑定都会不成功:
if let firstNumber = Int("4"), secondNumber = Int("42") where irstNumber < secondNumber {
print("\(firstNumber) < \(secondNumber)")
}
// Prints "4 < 42"
- 隐式解析可选类型(Implicitly Unwrapped Optional)(也不知道是不是叫这个名字)
有些变量在声明的时候就已经有值了,如果还是每次都判断是否为空就会非常低效,所以就有了这个Implicity Unwrapped Optional类型,意思就是我声明的这个变量不为空,用感叹号表示(!)。
下面这个🌰展示了Optionals和Implicity Unwrapped Optional的区别:
let possibleString: String? = "An optional string."
let forcedString: String = possibleString! // requires an exclamation mark
let assumedString: String! = "An implicitly unwrapped optional string."
let implicitString: String = assumedString // no need for an exclamation mark
同样的,你可以判断隐式解析可选类型是否为空(nil),也可以进行可选绑定。
🌰:
if assumedString != nil {
print(assumedString)
}
// Prints "An implicitly unwrapped optional string."
if let definiteString = assumedString {
print(definiteString)
}
// Prints "An implicitly unwrapped optional string."
异常处理(Error Handling)
当一个方法遇到错误情况,它就会抛出(throws)一个错误。而方法的调用者就会捕捉(catch)到错误信息,并及时处理。
func canThrowAnError() throws {
//this function may or may not throw an error
}
当一个方法可以抛出错误的时候在它声明方法名的时候要包括"throws"关键字。当你调用一个可以抛出错误的方法时,在前面用"try"关键字来修饰。
Swift会自动将错误信息从当先这个范围传递出去,知道会遇到"catch"子句的时候才会进行处理。
do {
try canThrowAnError()
//no error was thrown
} catch {
//an error was thrown
}
"do"状态创建了一个新的可以允许错误信息传递给一个或者多个"catch"子句的包含范围。
🌰:
func makeASandwich() throws {
// ...
}
do {
try makeASandwich()
eatASandwich()
} catch SandwichError.outOfCleanDishes {
washDishes()
} catch SandwichError.missingIngredients(let ingredients) {
buyGroceries(ingredients)
}
上面这个🌰中,"makeASandewich()"将会在没有干净盘子的时候执行"washDishes()"。之所以"makeASandwich()"可以抛出一个错误,是因为这个方法包含了"try"表达式。如果没有错误抛出,那么"eatASandwich()"这个方法就会执行。
-
断言(Assertions)
在某些情况下,如果一个特定的条件不满足,那么代码就不会继续执行。在这些情况下,你可以在你的代码中设置一个断言(asserttion)来结束代码的执行或者提供一个调试值为空或者不存在的机会。- 用断言进行调试(Debug with Assertions)
assertion会在runtime检查一个Boolean表达式的值是否为true。字面的意思就是,一个assertion"断言"一个表达式是否为真。如果表达式的值为true,那么代码会照常执行,如果表达式的值为false,代码执行结束,app会直接终止。
但你在调试情况下使用assertions,可以附加一条自己的信息。在Swift标准库中,调用"assert(::file:line:)"方法,这是一个全球变量:
- 用断言进行调试(Debug with Assertions)
let age = -3
assert(age >= 0, "A person's age cannot be less than zero")
//this causes the assertion to trigger, because age is not >= 0
assertions的信息也可以省略。
assert(age >= 0)
- 什么时候使用断言(When to Use Assertions)
使用assertions首先要确保表达是的值有可能为false,但是想要代码继续执行的话,值一定为true。以下几种情况适用assertions:- 一个整数下标索引值传到了一个自定义的下标实现,而值超出了范围(太小或太大)。
- 给函数传入一个值,但是非法的值可能导致函数不能正常执行。
- 一个可选值现在为nil,但是代码需要一个不为nil的值才能成功执行。
网友评论