Swift-基础部分,常量、变量、注解、整数、浮点数、类型转换、布尔值、元组、可选类型、强制解析、可选绑定、错误处理、断言、先决条件

1. 常量和变量

常量的值一旦设定就不能改变,而变量的值可以随意更改。

1.1 声明常量和变量

  • 常量和变量必须在使用前声明。
  • 用 let 来声明常量。
  • 用 var 来声明变量。
let a = 10
var b = 0
// 可以在一行中声明多个常量或者多个变量,用逗号隔开:
var x = 0.0, y = 0.0, z = 0.0

1.2 类型注解

  • 当你声明常量或者变量的时候可以加上类型注解(type annotation),说明常量或者变量中要存储的值的类型。
// 声明一个类型为 String ,名字为 message 的变量
var message: String
// 可以在一行中定义多个同样类型的变量,用逗号分割,并在最后一个变量名之后添加类型注解
var red, green, blue: Double

1.3 输出常量和变量

let age = 10
let name = "jelly"
// Swift 用字符串插值(string interpolation)的方式把常量名或者变量名当做占位符加入到长字符串中
print("\(b) have \(age) years old.")

2. 分号

  • Swift 并不强制要求你在每条语句的结尾处使用分号。
  • 有一种情况下必须要用分号,即你打算在同一行内写多条独立的语句:
 let a = 10 ; print(a)

3. 整数

Swift 提供了8、16、32和64位的有符号和无符号整数类型。

3.1 整数范围

  • 访问不同整数类型的 min 和 max 属性来获取对应类型的最小值和最大值:
// minValue 为 0,是 UInt8 类型
let minValue = UInt8.min  
// maxValue 为 255,是 UInt8 类型
let maxValue = UInt8.max  

3.2 Int

Swift 提供了一个特殊的整数类型 Int,特殊的无符号类型 UInt,长度与当前平台的原生字长相同:

  • 在32位平台上,Int 和 Int32 长度相同;UInt 和 UInt32 长度相同。
  • 在64位平台上,Int 和 Int64 长度相同;UInt 和 UInt64 长度相同。

尽量不要使用 UInt,除非你真的需要存储一个和当前平台原生字长相同的无符号整数。除了这种情况,最好使用 Int,即使你要存储的值已知是非负的。统一使用 Int 可以提高代码的可复用性,避免不同类型数字之间的转换,并且匹配数字的类型推断,

3.3 浮点数

  • Double 表示64位浮点数。当需要存储很大或者高精度的浮点数时使用此类型。
  • Float 表示32位浮点数。精度要求不高的话可以使用此类型。

4. 类型安全和类型推断

  • Swift 是一个类型安全(type safe)的语言。类型安全的语言可以让你清楚地知道代码要处理的值的类型。如果你的代码需要一个 String,你绝对不可能不小心传进去一个 Int
  • Swift 会使用类型推断(type inference)来选择合适的类型。有了类型推断,编译器可以在编译代码的时候自动推断出表达式的类型。原理很简单,只要检查你赋的值即可。
let a = 10  //  被推测为 Int 类型
let b = 3.1415926   //  被推测为 Double 类型
let c = 3 + 0.1415926   //  被推测为 Double 类型

5. 数值型字面量

  • 十进制数:没有前缀
  • 二进制数:前缀是 0b
  • 八进制数:前缀是 0o
  • 十六进制数:前缀是 0x
let decimalInteger = 17
let binaryInteger = 0b10001       // 二进制的17
let octalInteger = 0o21           // 八进制的17
let hexadecimalInteger = 0x11     // 十六进制的17

十进制浮点数也可以有一个可选的指数(exponent),通过大写或者小写的 e 来指定;十六进制浮点数必须有一个指数,通过大写或者小写的 p 来指定。

  • 如果一个十进制数的指数为 exp,那这个数相当于基数和10^exp 的乘积:

1.25e2 表示 1.25 × 10^2,等于 125.0。
1.25e-2 表示 1.25 × 10^-2,等于 0.0125。

  • 如果一个十六进制数的指数为 exp,那这个数相当于基数和2^exp 的乘积:

0xFp2 表示 15 × 2^2,等于 60.0。
0xFp-2 表示 15 × 2^-2,等于 3.75。

let a= 12.1875  //  12.1875
let b= 1.21875e1    //  12.1875
let c= 0xC.3p0  //  12.1875

//  数值类字面量可以包括额外的格式来增强可读性。整数和浮点数都可以添加额外的零并且包含下划线,并不会影响字面量
let h= 000123.456
let i= 1_000_000
let j= 1_000_000.000_000_1

6. 数值型类型转换

6.1 整数转换

不同整数类型的变量和常量可以存储不同范围的数字。

  • Int8 类型: -128 --127
  • UInt8 类型: 0~255。

如果数字超出了常量或者变量可存储的范围,编译的时候会报错

let a: UInt16 = 2_000
let b: UInt8 = 1
let c= a+ UInt16(b)

6.2整数和浮点数转换

  • 整数和浮点数的转换必须显式指定类型
let a= 3
let b= 0.14159
let c = Double(a) + b   // pi 等于 3.14159,所以被推测为 Double 类型
  • 浮点数到整数的反向转换
let a= 3.14159
let b= Int(a)   // integerPi 等于 3,所以被推测为 Int 类型

7. 类型别名

类型别名(type aliases)就是给现有类型定义另一个名字。

typealias GDUInt16 = UInt16
var a = GDUInt16.min    // a 现在是 0

8. 布尔值

Swift 有两个布尔常量,truefalse

let a = true
if a {
    print("true")
} else {
    print("false")
}
// 输出“true”

9. 元组

元组(tuples)把多个值组合成一个复合值。元组内的值可以是任意类型,并不要求是相同类型。

  • http404Error 的类型是 (Int, String),值是 (404, "Not Found")
let http404Error = (404, "Not Found")
  • 可以将一个元组的内容分解(decompose)成单独的常量和变量,然后就可以正常使用它们了:
let (statusCode, statusMessage) = http404Error
print("The status code is \(statusCode)")   // 输出“The status code is 404”
print("The status message is \(statusMessage)") // 输出“The status message is Not Found”
  • 如果你只需要一部分元组值,分解的时候可以把要忽略的部分用下划线(_)标记
let (justTheStatusCode, _) = http404Error
print("The status code is \(justTheStatusCode)")    // 输出“The status code is 404”
  • 可以通过下标来访问元组中的单个元素,下标从零开始:
print("The status code is \(http404Error.0)")   // 输出“The status code is 404”
print("The status message is \(http404Error.1)")    // 输出“The status message is Not Found”
注意:
    当遇到一些相关值的简单分组时,元组是很有用的。元组不适合用来创建复杂的数据结构。如果你的数据结构比较复杂,不要使用元组,用类或结构体去建模。

9. 可选类型

可选类型(optionals)来处理值可能缺失的情况。可选类型表示两种可能: 或者有值, 或者根本没有值

  • Swift 的 Int 类型有一种构造器,作用是将一个 String 值转换成一个 Int 值。然而,并不是所有的字符串都可以转换成一个整数。字符串 "123" 可以被转换成数字 123 ,但是字符串 "hello, world" 不行。
let possibleNumber = "123"
let convertedNumber = Int(possibleNumber)   // convertedNumber 被推测为类型 "Int?", 或者类型 "optional Int"
注意:
    因为该构造器可能会失败,所以它返回一个可选类型(optional)Int,而不是一个 Int。一个可选的 Int 被写作 Int? 而不是 Int。问号暗示包含的值是可选类型,也就是说可能包含 Int 值也可能不包含值。(不能包含其他任何值比如 Bool 值或者 String 值。只能是 Int 或者什么都没有。)

9.1 nil

  • 可以给可选变量赋值为 nil 来表示它没有值:
var serverResponseCode: Int? = 404  // serverResponseCode 包含一个可选的 Int 值 404
serverResponseCode = nil    // serverResponseCode 现在不包含值
注意:
    nil 不能用于非可选的常量和变量。如果你的代码中有常量或者变量需要处理值缺失的情况,请把它们声明成对应的可选类型。
  • 如果你声明一个可选常量或者变量但是没有赋值,它们会自动被设置为 nil:
var surveyAnswer: String?   // surveyAnswer 被自动设置为 nil
注意:
    Swift 的 nil 和 Objective-C 中的 nil 并不一样。在 Objective-C 中,nil 是一个指向不存在对象的指针。在 Swift 中,nil 不是指针——它是一个确定的值,用来表示值缺失。任何类型的可选状态都可以被设置为 nil,不只是对象类型。

9.2 强制解析

当你确定可选类型确实包含值之后,你可以在可选的 名字后面加一个感叹号(!)来获取值 。这个惊叹号表示“我知道这个可选有值,请使用它。”这被称为可选值的强制解析(forced unwrapping)。

if convertedNumber != nil {
    print("convertedNumber has an integer value of \(convertedNumber!).")
}
注意
    使用 ! 来获取一个不存在的可选值会导致运行时错误。使用 ! 来强制解析值之前,一定要确定可选包含一个非 nil 的值。

9.3 可选绑定

  • 使用可选绑定(optional binding)来判断可选类型是否包含值,如果包含就把值赋给一个临时常量或者变量。
//  如果 someOptional  包含一个值,创建一个叫做 constantName 的新常量并将可选包含的值赋给它。”
if let constantName = someOptional {
    //  如果转换成功,constantName 常量可以在 if 语句的第一个分支中使用。它已经被可选类型 包含的 值初始化过,所以不需要再使用 ! 后缀来获取它的值。
}
  • 可包含多个可选绑定或多个布尔条件在一个 if 语句中,只要使用逗号分开就行。只要有任意一个可选绑定的值为 nil,或者任意一个布尔条件为 false,则整个 if 条件判断为 false,这时你就需要使用嵌套 if 条件语句来处理:
if let firstNumber = Int("4"), let secondNumber = Int("42"), firstNumber < secondNumber && secondNumber < 100 {
    print("\(firstNumber) < \(secondNumber) < 100")
}   // 输出“4 < 42 < 100”

if let firstNumber = Int("4") {
    if let secondNumber = Int("42") {
        if firstNumber < secondNumber && secondNumber < 100 {
            print("\(firstNumber) < \(secondNumber) < 100")
        }
    }
}   // 输出“4 < 42 < 100”
注意
    在 if 条件语句中使用常量和变量来创建一个可选绑定,仅在 if 语句的句中(body)中才能获取到值。相反,在 guard 语句中使用常量和变量来创建一个可选绑定,仅在 guard 语句外且在语句后才能获取到值。

9.4 隐式解析可选类型

  • 有时候在程序架构中,第一次被赋值之后,可以确定一个可选类型总会有值。在这种情况下,每次都要判断和解析可选值是非常低效的,因为可以确定它总会有值。这种类型的可选状态被定义为隐式解析可选类型(implicitly unwrapped optionals)
  • 声明:把想要用作可选的类型的后面的问号(String?)改成感叹号(String!)来声明一个隐式解析可选类型。
  • 一个隐式解析可选类型其实就是一个普通的可选类型,但是可以被当做非可选类型来使用,并不需要每次都使用解析来获取可选值。
let possibleString: String? = "An optional string."
let forcedString: String = possibleString! // 需要感叹号来获取值

let assumedString: String! = "An implicitly unwrapped optional string."
let implicitString: String = assumedString  // 不需要感叹号
注意
    如果一个变量之后可能变成 nil 的话请不要使用隐式解析可选类型。如果你需要在变量的生命周期中判断是否是 nil 的话,请使用普通可选类型。

10. 错误处理

使用 错误处理(error handling) 来应对程序执行中可能会遇到的错误条件。错误处理可以推断失败的原因,并传播至程序的其他部分。

  • 当一个函数遇到错误条件,它能报错。调用函数的地方能抛出错误消息并合理处理。
func canThrowAnError() throws {
    // 这个函数有可能抛出错误
}
  • 一个函数可以通过在声明中添加 throws 关键词来抛出错误消息。当你的函数能抛出错误消息时,你应该在表达式中前置 try 关键词。
do {
    try canThrowAnError()
    // 没有错误消息抛出
} catch {
    // 有一个错误消息抛出
}
  • 一个 do 语句创建了一个新的包含作用域,使得错误能被传播到一个或多个 catch 从句。
    这里有一个错误处理如何用来应对不同错误条件的例子。
func makeASandwich() throws {
    // ...
}

do {
    try makeASandwich()
    eatASandwich()
} catch SandwichError.outOfCleanDishes {
    washDishes()
} catch SandwichError.missingIngredients(let ingredients) {
    buyGroceries(ingredients)
}
  • 在此例中,makeASandwich()(做一个三明治)函数会抛出一个错误消息如果没有干净的盘子或者某个原料缺失。因为 makeASandwich() 抛出错误,函数调用被包裹在 try 表达式中。将函数包裹在一个 do 语句中,任何被抛出的错误会被传播到提供的 catch 从句中。
  • 如果没有错误被抛出,eatASandwich() 函数会被调用。如果一个匹配 SandwichError.outOfCleanDishes 的错误被抛出,washDishes() 函数会被调用。如果一个匹配 SandwichError.missingIngredients 的错误被抛出,buyGroceries(_:) 函数会被调用,并且使用 catch 所捕捉到的关联值 [String] 作为参数。

11. 断言和先决条件

  • 断言和先决条件是在运行时所做的检查。
  • 断言帮助你在开发阶段找到错误和不正确的假设。断言仅在调试环境运行。
  • 先决条件帮助你在生产环境中探测到存在的问题。先决条件则在调试环境和生产环境中运行。
  • 在生产环境中,断言的条件将不会进行评估。这个意味着你可以使用很多断言在你的开发阶段,但是这些断言在生产环境中不会产生任何影响。

11.1使用断言进行调试

  • 可以调用 Swift 标准库的 assert(::file:line:) 函数来写一个断言。向这个函数传入一个结果为 true 或者 false 的表达式以及一条信息,当表达式的结果为 false 的时候这条信息会被显示:
let age = -3
assert(age >= 0, "A person's age cannot be less than zero") // 因为 age < 0,所以断言会触发
  • 只有 age >= 0 为 true 时,即 age 的值非负的时候,代码才会继续执行。
  • 如果 age 的值是负数,就像代码中那样,age >= 0 为 false,断言被触发,终止应用。
  • 如果不需要断言信息,可以就像这样忽略掉:
assert(age >= 0)
  • 如果代码已经检查了条件,你可以使用 assertionFailure(_:file:line:) 函数来表明断言失败了,例如:
if age > 10 {
    print("You can ride the roller-coaster or the ferris wheel.")
} else if age > 0 {
    print("You can ride the ferris wheel.")
} else {
    assertionFailure("A person's age can't be less than zero.")
}

11.2 强制执行先决条件

当一个条件可能为假,但是继续执行代码要求条件必须为真的时候,需要使用先决条件。

例如: 使用先决条件来检查是否下标越界,或者来检查是否将一个正确的参数传给函数。

  • 你可以使用全局 precondition(::file:line:) 函数来写一个先决条件。向这个函数传入一个结果为 true 或者 false 的表达式以及一条信息,当表达式的结果为 false 的时候这条信息会被显示:
// 在一个下标的实现里...
precondition(index > 0, "Index must be greater than zero.")
  • 你可以调用 preconditionFailure(_:file:line:) 方法来表明出现了一个错误,例如,switch 进入了 default 分支,但是所有的有效值应该被任意一个其他分支(非 default 分支)处理。

      注意
          如果你使用 unchecked 模式(-Ounchecked)编译代码,先决条件将不会进行检查。编译器假设所有的先决条件总是为 true(真),他将优化你的代码。然而,fatalError(_:file:line:) 函数总是中断执行,无论你怎么进行优化设定。
    
  • 你能使用 fatalError(_:file:line:) 函数在设计原型和早期开发阶段,这个阶段只有方法的声明,但是没有具体实现,你可以在方法体中写上 fatalError("Unimplemented")作为具体实现。因为 fatalError 不会像断言和先决条件那样被优化掉,所以你可以确保当代码执行到一个没有被实现的方法时,程序会被中断。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值