swift变量
1. swift的基本变量类型
swift 的变量类型和OC、C基本相似,int = 整形, double = 双精度浮点 , float = 单精度浮点, string = 字符串, bool = 布尔值,
swift中一行结束不需要使用 ; ,但是如果两句代码写到同一行,就需要用 ; 隔开
2.swift属性声明
和OC不同,swift的属性分为变量和常量,用let 声明常量,用var声明变量,常量的值不可更改。
属性注释
var welcomeMessage: String
如上代码, : 表示的是属性类型,上面声明的是一个 String类型的变量,变量名是welcomeMessage
welcomeMessage只能赋值为字符串。
也可以定义多个相同类型的属性,中间用逗号隔开
var red, green, blue: Double
如上,定义了三个 Double类型的变量。
swift有变量类型推导,所以基本上不用定义类型,比如
var text = 10
这时text就是int类型的。
变量名可以包括任意字符,甚至Unicode,和汉语,常量和变量名称不能包含空白字符,数学符号,箭头,专用(或无效)Unicode代码点或线条和框图字符。也不能以数字开头,尽管数字可能包含在名字的其他地方。
一旦声明了某个类型的常量或变量,就不能再声明它的名字,或者改变它来存储不同类型的值。你也不能把一个常量变成一个变量或一个常量变量。
打印函数为Print()
print(_:separator:terminator:)
函数是一个全局函数,它将一个或多个值打印到适当的输出。例如,在Xcode中,该print(_:separator:terminator:)
函数在Xcode的“控制台”窗格中输出其输出。该separator
和terminator
参数都有默认值,所以当你调用这个函数,你可以忽略它们。默认情况下,函数通过添加换行符来终止打印的行。要打印一个没有换行符的值,传递一个空字符串作为终止符 - 例如print(someValue, terminator: "")
。
Swift使用字符串插值将常量或变量的名称作为占位符包含在较长的字符串中,并提示Swift将其替换为该常量或变量的当前值。用圆括号将名称包装起来,并在左括号之前用反斜杠进行转义:
print("The current value of friendlyWelcome is \(friendlyWelcome)")
// Prints "The current value of friendlyWelcome is Bonjour!"
注释
使用注释在代码中包含不可执行的文本,作为注释或提醒。在编译代码时,Swift编译器会忽略注释。
Swift中的注释与C中的注释非常相似。单行注释以两个正斜杠(//
)开头:
// This is a comment.
多行注释以正斜杠开始,后跟星号(/*
),以星号结尾,后跟正斜杠(*/
):
/* This is also a comment
but is written over multiple lines. */
与C中的多行注释不同,Swift中的多行注释可以嵌套在其他多行注释中。您可以通过启动多行注释块,然后在第一个块内开始第二个多行注释来编写嵌套注释。然后关闭第二个块,然后关闭第一个块:
/* This is the start of the first multiline comment.
/* This is the second, nested multiline comment. */
This is the end of the first multiline comment. */
嵌套的多行注释使您能够快速轻松地注释大量代码,即使代码已经包含多行注释。
分号
与许多其他语言不同,Swift不需要;
在代码中的每个语句之后都写一个分号(),尽管如果你愿意的话可以这样做。但是,如果要在一行中编写多个单独的语句,则需要使用分号:
let cat = "🐱"; print(cat)
// Prints "🐱"
整型
整数是没有小数部分的整数,如42
和-23
。整数有符号(正数,零或负数)或无符号数(正数或零)。
Swift提供了8,16,32和64位格式的有符号和无符号整数。这些整数遵循类似于C的命名约定,其中8位无符号整数是类型的UInt8
,32位有符号整数是类型的Int32
。像Swift中的所有类型一样,这些整数类型都有大写的名字。
整数界限
你可以用它来访问每个整数类型的最小值和最大值min
和max
特性:
let minValue = UInt8.min // minValue is equal to 0, and is of type UInt8
let maxValue = UInt8.max // maxValue is equal to 255, and is of type UInt8
这些属性的值是适当大小的数字类型(UInt8
例如上面的示例中),因此可以在表达式中与其他相同类型的值一起使用。
诠释
在大多数情况下,您不需要选择要在代码中使用的特定大小的整数。Swift提供了一个额外的整数类型,Int
它与当前平台的本地字大小大小相同:
-
在一个32位平台上,
Int
尺寸与Int32
。 -
在64位平台上,
Int
尺寸与Int64
。
除非需要使用特定大小的整数,否则请Int
在代码中使用整数值。这有助于代码的一致性和互操作性。即使在32位平台上,Int
也可以存储-2,147,483,648
和之间的任意值2,147,483,647
,并且对于很多整数范围来说足够大。
UINT
Swift还提供了一个无符号整数类型,UInt
它的大小与当前平台的本地字大小相同:
-
在一个32位平台上,
UInt
尺寸与UInt32
。 -
在64位平台上,
UInt
尺寸与UInt64
。
注意
UInt
仅在您特别需要与平台的本机字大小相同的无符号整数类型时才使用。如果不是这种情况,Int
即使要知道存储的值是非负的,也是优选的。Int
整数值的一致使用有助于代码的互操作性,避免了在不同数字类型之间进行转换的需要,并匹配整数类型推断,如类型安全和类型推断中所述。
浮点数字
浮点数是具有小数部分的数字,例如3.14159
,0.1
,和-273.15
。
浮点类型可以表示比整数类型更广泛的数值范围,并且可以存储比可以存储在数组中更大或更小的数字Int
。Swift提供了两个有符号的浮点数类型:
-
Double
代表一个64位的浮点数。 -
Float
表示一个32位的浮点数。
类型安全和类型推断
Swift是一个类型安全的语言。类型安全的语言鼓励你清楚你的代码可以使用的值的类型。如果你的代码的一部分需要一个String
,你不能Int
错误地通过它。
因为Swift是类型安全的,所以它在编译代码时执行类型检查,并将任何不匹配的类型标记为错误。这使您能够在开发过程中尽早捕获并修复错误。
类型检查有助于避免在使用不同类型的值时发生错误。但是,这并不意味着你必须指定你声明的每个常量和变量的类型。如果你不指定你需要的值的类型,Swift使用类型推断来计算出适当的类型。类型推断使编译器能够在编译代码时自动推断特定表达式的类型,只需检查您提供的值即可。
由于类型推理,与C或Objective-C等语言相比,Swift所需的类型声明要少得多。常量和变量仍然是明确的类型,但是很多指定类型的工作都是为你完成的。
当你用一个初始值声明一个常量或变量时,类型推断特别有用。这通常是通过在声明它的点处为常量或变量赋予一个文字值(或文字)来完成的。(A字面值是直接出现在源代码中,如一个值42
和3.14159
在下面的例子。)
例如,如果你将一个42
新的常量赋值给一个新的常量,而没有说明它是什么类型的话,那么Swift推断你想让这个常量成为一个常量Int
,因为你用一个看起来像一个整数的数字来初始化它:
let meaningOfLife = 42
// meaningOfLife is inferred to be of type Int
同样,如果你没有为浮点数指定一个类型,Swift会推断你想创建一个Double
:
let pi = 3.14159
// pi is inferred to be of type Double
当推断浮点数的类型时, Swift总是选择Double
(而不是Float
)。
如果在表达式中结合整数和浮点文字,Double
将从上下文中推断出一种类型:
let anotherPi = 3 + 0.14159
// anotherPi is also inferred to be of type Double
字面值3
没有明确的类型本身,所以Double
从浮点文字的存在推断出适当的输出类型作为加法的一部分。
数字文字
整数文字可以写成:
-
一个十进制数,没有前缀
-
一个二进制数字,带有
0b
前缀 -
一个八进制数,有
0o
前缀 -
一个十六进制数,有
0x
前缀
所有这些整数文字都有一个十进制值17
:
let decimalInteger = 17
let binaryInteger = 0b10001 // 17 in binary notation
let octalInteger = 0o21 // 17 in octal notation
let hexadecimalInteger = 0x11 // 17 in hexadecimal notation
浮点文字可以是十进制(不带前缀)或十六进制(带0x
前缀)。它们必须在小数点的两侧始终有一个数字(或十六进制数字)。十进制浮点数也可以有一个可选的指数,用大写或小写表示e
; 十六进制浮点数必须有一个指数,用大写或小写表示p
。
对于指数为的十进制数exp
,基数乘以10 exp:
-
1.25e2
意味着1.25 x 10 2,或125.0
。 -
1.25e-2
意味着1.25 x 10 -2,或者0.0125
。
对于指数为的十六进制数exp
,基数乘以2 exp:
-
0xFp2
指15 x 2 2,或60.0
。 -
0xFp-2
指的是15 x 2 -2,或者3.75
。
所有这些浮点文字都有十进制值12.1875
:
let decimalDouble = 12.1875
let exponentDouble = 1.21875e1
let hexadecimalDouble = 0xC.3p0
数字文字可以包含额外的格式,以方便阅读。整数和浮点数都可以用额外的零填充,并且可以包含下划线来帮助提高可读性。这两种格式都不影响字面值的基础值:
let paddedDouble = 000123.456
let oneMillion = 1_000_000
let justOverOneMillion = 1_000_000.000_000_1
数字类型转换
Int
在代码中 使用所有通用整数常量和变量的类型,即使它们已知是非负的。在日常情况下使用默认的整数类型意味着整型常量和变量可以在您的代码中立即互操作,并且将与整型文字值的推断类型相匹配。
仅当手头任务特别需要使用其他整数类型时,才能使用其他整数类型,这是因为来自外部源的显式大小的数据,或性能,内存使用情况或其他必要的优化。在这些情况下使用明确大小的类型有助于捕获任何意外的值溢出,并隐含地记录正在使用的数据的性质。
整数转换
可以存储在整数常量或变量中的数字范围对于每种数字类型都是不同的。一个Int8
常数或变量可以存储之间的数字-128
和127
,而UInt8
常数或变量可以存储之间的数字0
和255
。在编译代码时,不能将其放入常量或变量的大小的整数类型中会报告为错误:
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
由于每种数字类型都可以存储不同范围的值,因此您必须逐个选择数字类型转换。这种选择加入方法可以防止隐藏的转换错误,并有助于在代码中明确类型转换意图。
要将一个特定的号码类型转换为另一个号码类型,您需要使用现有的值初始化一个所需类型的新号码。在下面的例子中,常量twoThousand
是类型的UInt16
,而常量one
是类型的UInt8
。他们不能直接加在一起,因为他们不是同一类型的。相反,这个例子调用UInt16(one)
创建一个新UInt16
值one
,并用这个值代替原来的值:
let twoThousand: UInt16 = 2_000
let one: UInt8 = 1
let twoThousandAndOne = twoThousand + UInt16(one)
因为添加的两边都是现在的类型UInt16
,所以允许添加。输出常量(twoThousandAndOne
)被推断为是类型的UInt16
,因为它是两个UInt16
值的总和。
SomeType(ofInitialValue)
是调用Swift类型的初始值设定项并传入初始值的默认方式。在幕后,UInt16
有一个接受一个UInt8
值的初始化器,所以这个初始化器被用来UInt16
从现有的一个新的UInt8
。你不能在这里传入任何类型,但是它必须是一个UInt16
提供初始化的类型。扩展现有类型以提供接受新类型(包括您自己的类型定义)的初始化方法在扩展中介绍。
整数和浮点转换
整数和浮点数字类型之间的转换必须明确:
let three = 3
let pointOneFourOneFiveNine = 0.14159
let pi = Double(three) + pointOneFourOneFiveNine
// pi equals 3.14159, and is inferred to be of type Double
在这里,常量的值three
被用来创建一个新的类型值Double
,所以添加的两边是相同的类型。如果没有这个转换,不允许增加。
浮点到整数转换也必须明确。整数类型可以使用Double
或Float
值来初始化:
let integerPi = Int(pi)
// integerPi equals 3, and is inferred to be of type Int
当用这种方式初始化一个新的整数值时,浮点值总是被截断的。这意味着4.75
变成4
,-3.9
变成-3
。
类型别名
类型别名为现有类型定义了一个替代名称。您可以使用typealias
关键字定义类型别名。
如果要通过上下文更合适的名称引用现有类型,例如在从外部源处理特定大小的数据时,类型别名很有用:
typealias AudioSample = UInt16
一旦你定义了一个类型别名,你可以在任何你可能使用原始名称的地方使用别名:
var maxAmplitudeFound = AudioSample.min
// maxAmplitudeFound is now 0
这里AudioSample
被定义为一个别名UInt16
。因为它是一个别名,AudioSample.min
实际调用的调用UInt16.min
,它提供0
了maxAmplitudeFound
变量的初始值。
布尔
Swift有一个基本的布尔类型,叫做Bool
。布尔值被称为逻辑,因为它们只能是真或假。Swift提供了两个布尔常量值,true
并且false
:
let orangesAreOrange = true
let turnipsAreDelicious = false
根据它们用布尔文字值初始化的事实推断了这些类型orangesAreOrange
和turnipsAreDelicious
已经被推断出来Bool
。正如Int
和Double
上面,你并不需要声明常量或变量Bool
,如果将其设置为true
或false
为您创建它们尽快。类型推断有助于使Swift代码在使用其他已知类型的值初始化常量或变量时更加简洁易读。
当您使用条件语句(如if
语句)时,布尔值特别有用:
if turnipsAreDelicious {
print("Mmm, tasty turnips!")
} else {
print("Eww, turnips are horrible.")
}
// Prints "Eww, turnips are horrible."
控制流程if
中更详细地介绍了 诸如声明等条件语句。
Swift的类型安全性可以防止非布尔值被替换Bool
。以下示例报告编译时错误:
let i = 1
if i {
// this example will not compile, and will report an error
}
但是,下面的替代示例是有效的:
let i = 1
if i == 1 {
// this example will compile successfully
}
i == 1
比较 的结果是类型的Bool
,所以这个第二个例子通过类型检查。比较像i == 1
在基本操作符中讨论。
就像Swift中的其他类型安全例子一样,这种方法避免了意外错误,并确保特定代码段的意图总是清晰的。
元组
元组将多个值组合为一个复合值。元组中的值可以是任何类型,不必是彼此相同的类型。
在这个例子中,(404, "Not Found")
是一个描述HTTP状态码的元组。每当您请求网页时,HTTP状态码都是由Web服务器返回的特殊值。404 Not Found
如果您请求不存在的网页,则会返回状态代码。
let http404Error = (404, "Not Found")
// http404Error is of type (Int, String), and equals (404, "Not Found")
这个(404, "Not Found")
元组将an Int
和a 分组在一起String
,为HTTP状态码提供了两个独立的值:一个数字和一个人类可读的描述。它可以被描述为“一个类型的元组(Int, String)
”。
你可以从任何类型的排列中创建元组,并且可以包含尽可能多的不同类型。没有什么阻止你有型的元组(Int, Int, Int)
,或者(String, Bool)
,或者你确实需要的任何其他排列。
你可以将一个元组的内容分解成单独的常量或变量,然后像往常一样访问:
let (statusCode, statusMessage) = http404Error
print("The status code is \(statusCode)")
// Prints "The status code is 404"
print("The status message is \(statusMessage)")
// Prints "The status message is Not Found"
如果您只需要某些元组的值,则_
在分解元组时,请使用下划线()忽略部分元组:
let (justTheStatusCode, _) = http404Error
print("The status code is \(justTheStatusCode)")
// Prints "The status code is 404"
或者,使用从零开始的索引号访问元组中的各个元素值:
print("The status code is \(http404Error.0)")
// Prints "The status code is 404"
print("The status message is \(http404Error.1)")
// Prints "The status message is Not Found"
当定义元组时,可以将元组中的各个元素命名为:
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"
元组作为函数的返回值特别有用。尝试检索网页的函数可能会返回(Int, String)
元组类型来描述页面检索的成功或失败。通过返回具有两个不同类型的值的元组,每个不同类型的函数都提供了有关其结果的更多有用信息,而不是仅返回单个类型的单个值。有关更多信息,请参阅具有多个返回值的函数。
选配
在价值可能不存在的情况下 使用可选项。可选的代表两种可能性:要么有是一个值,你可以解开可选的访问值,或者有没有价值可言。
注意
C或Objective-C中不存在可选项的概念。Objective-C中最接近的东西是nil
从一个方法返回的能力,否则返回一个对象,nil
意思是“缺少一个有效的对象”。但是,这只适用于对象 - 它不适用于结构,基本C类型或枚举值。对于这些类型,Objective-C方法通常会返回一个特殊值(如NSNotFound
)来指示缺少值。这种方法假设方法的调用者知道有一个特殊的值来测试,并记得检查它。Swift的选项可以让你指出没有任何类型的值,而不需要特殊的常量。
以下是如何使用可选项来应对价值缺失的一个例子。Swift的Int
类型有一个初始化器,它试图将一个String
值转换成一个Int
值。但是,并不是每个字符串都可以转换成一个整数。该字符串"123"
可以转换为数字值123
,但字符串"hello, world"
没有明显的数值转换。
下面的例子使用初始化器来尝试将a String
转换为Int
:
let possibleNumber = "123"
let convertedNumber = Int(possibleNumber)
// convertedNumber is inferred to be of type "Int?", or "optional Int"
因为初始化器可能失败,所以它返回一个可选的 Int
,而不是一个Int
。可选Int
是写成Int?
,而不是Int
。问号表示它所包含的值是可选的,这意味着它可能包含一些 Int
值,或者它可能根本不包含任何值。(它不能包含任何其他的东西,比如Bool
值或String
值,它可以是一个Int
,或者什么也不是。)
零
通过给可选变量赋予一个特殊值来设置一个可选变量nil
:
var serverResponseCode: Int? = 404
// serverResponseCode contains an actual Int value of 404
serverResponseCode = nil
// serverResponseCode now contains no value
如果您定义了一个可选变量而不提供默认值,则会自动nil
为您设置该变量:
var surveyAnswer: String?
// surveyAnswer is automatically set to nil
注意
Swift nil
和nil
Objective-C 不一样。在Objective-C中,nil
是一个指向不存在对象的指针。在Swift中,nil
不是一个指针,而是缺少某种类型的值。选配的任何类型可以设置为nil
,不只是对象类型。
如果陈述和强制解包
您可以使用if
语句通过比较可选的against来确定可选是否包含值nil
。您使用“等于”运算符(==
)或“不等于”运算符(!=
)执行此比较。
如果可选值有一个值,则认为它是“不等于” nil
:
if convertedNumber != nil {
print("convertedNumber contains some integer value.")
}
// Prints "convertedNumber contains some integer value."
一旦确定可选的确实包含一个值,就可以通过!
在可选名称的末尾添加一个感叹号()来访问其基础值。感叹号有效地说:“我知道这个可选肯定有价值,请使用它“。这被称为强制展开可选的值:
if convertedNumber != nil {
print("convertedNumber has an integer value of \(convertedNumber!).")
}
// Prints "convertedNumber has an integer value of 123."
有关详情if
,请参阅控制流程。
可选的绑定
您使用可选绑定来查找可选是否包含值,如果是,则使该值可用作临时常量或变量。可选的绑定可以if
和with while
语句一起用来检查一个可选的值,并把这个值提取到一个常量或变量中,作为单个动作的一部分。if
并while
在控制流程中更详细地描述报表。
为if
语句编写一个可选的绑定,如下所示:
-
如果 让 constantName = someOptional {
-
声明
-
}
您可以重写Optionals部分中的possibleNumber
示例以使用可选绑定而不是强制展开:
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"
这段代码可以读作:
“如果Int
返回的可选Int(possibleNumber)
值包含一个值,则设置一个新的常量调用actualNumber
可选值中包含的值。”
如果转换成功,则该actualNumber
常量在if
语句的第一个分支内可用。它已经被包含在可选项中的值初始化,所以不需要使用!
后缀来访问它的值。在这个例子中,actualNumber
只是用来打印转换的结果。
您可以使用可选绑定的常量和变量。如果您想操作语句actualNumber
第一个分支内的值if
,您可以if var actualNumber
改为写入,并且可选内容中的值将作为变量而不是常量提供。
您可以根据需要在单个if
语句中包含尽可能多的可选绑定和布尔条件,并用逗号分隔。如果可选绑定中的nil
任何值是或任何布尔条件的计算结果false
,则整个if
语句的条件被认为是false
。以下if
声明是等同的:
if let firstNumber = Int("4"), let secondNumber = Int("42"), firstNumber < secondNumber && secondNumber < 100 {
print("\(firstNumber) < \(secondNumber) < 100")
}
// Prints "4 < 42 < 100"
if let firstNumber = Int("4") {
if let secondNumber = Int("42") {
if firstNumber < secondNumber && secondNumber < 100 {
print("\(firstNumber) < \(secondNumber) < 100")
}
}
}
// Prints "4 < 42 < 100"
隐含解包选项
如上所述,可选项表示常数或变量被允许具有“无值”。可以使用if
语句来检查选项,以查看是否存在值,并且可以使用可选绑定有条件地解包,以访问可选值(如果存在)。
有时从程序的结构中可以清楚地看到,在第一次设置值之后,可选项将始终有一个值。在这些情况下,每次访问时都不需要检查和打开可选的值,因为可以安全地假定所有的时间都有一个值。
这些选项被定义为隐含的解包选项。你写一个隐式解开的可选项,在你想要的可选类型之后放置一个感叹号(String!
)而不是一个问号(String?
)。
当一个可选的值被确认在第一次定义的可选值之后立即存在时,隐式解包的可选值是有用的,并且可以肯定地假定在随后的每个点都存在。Swift中隐式解包选项的主要用途是在类初始化期间,如Unowned References和Unwinedly Unwrapped Optional Properties中所述。
隐式解包可选是幕后的普通可选项,但也可以像非可选值一样使用,而不必在每次访问时展开可选值。以下示例显示了在以可显式方式访问包装值时,可选字符串与隐式解包的可选字符串之间的行为差异String
:
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
你可以想象一个隐式解包的可选方法,只要使用它就可以自动解包这个可选方法。每次使用时,不要在可选名称后面放置感叹号,而是在声明它时在可选类型后面放置感叹号。
你仍然可以像一个普通的可选项那样对待一个隐式的解包可选,来检查它是否包含一个值:
if assumedString != nil {
print(assumedString)
}
// Prints "An implicitly unwrapped optional string."
你也可以使用一个带有可选绑定的隐式解包可选方法,在一个语句中检查和解包它的值:
if let definiteString = assumedString {
print(definiteString)
}
// Prints "An implicitly unwrapped optional string."
错误处理
您可以使用错误处理来响应您的程序在执行过程中可能遇到的错误情况。
与可选择性有关,它可以使用值的存在或不存在来传递函数的成功或失败,错误处理允许您确定失败的根本原因,并且,如果有必要,将错误传播到程序的另一部分。
当一个函数遇到一个错误条件时,它会抛出一个错误。然后该函数的调用者可以捕获错误并作出适当的响应。
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)
}
在这个例子中,makeASandwich()
如果没有可用的干净的菜肴,或者如果有任何配料丢失,该功能将会报错。因为makeASandwich()
可以抛出一个错误,函数调用被包装在一个try
表达式中。通过将函数调用包装在一个do
语句中,抛出的任何错误都会传播到提供的catch
子句中。
如果没有错误,eatASandwich()
则调用该函数。如果抛出一个错误,并匹配SandwichError.outOfCleanDishes
大小写,那么washDishes()
函数将被调用。如果抛出一个错误并且匹配SandwichError.missingIngredients
大小写,那么该buyGroceries(_:)
函数将被调用,并[String]
使用catch
模式捕获的相关值。
错误处理中 详细介绍了抛出,捕获和传播错误。
断言和先决条件
断言和先决条件是在运行时发生的检查。在执行任何进一步的代码之前,使用它们来确保满足基本条件。如果断言或前提条件中的布尔条件评估为true
,则代码执行将像往常一样继续。如果条件评估为false
,程序的当前状态是无效的; 代码执行结束,你的应用程序被终止。
您使用断言和先决条件来表达您所做的假设以及编码时的期望,这样您就可以将它们包含在代码中。断言有助于您在开发过程中发现错误和不正确的假设,并且先决条件可帮助您检测生产中的问题。
除了在运行时验证您的期望外,断言和先决条件也成为代码中有用的文档形式。与上述错误处理中讨论的错误条件不同,断言和先决条件不用于可恢复或预期的错误。因为失败的断言或先决条件表明一个无效的程序状态,没有办法赶上失败的断言。
使用断言和先决条件不能替代设计代码的方式,以至于不可能出现无效条件。但是,使用它们强制执行有效的数据和状态会导致您的应用程序在发生无效状态时更可预测地终止,并有助于使问题更易于调试。一旦检测到无效状态,立即停止执行也有助于限制由该无效状态造成的损害。
断言和先决条件之间的区别在于它们被检查时:只在调试版本中检查断言,但是在调试版本和生产版本中检查前提条件。在生产构建中,断言内的条件不被评估。这意味着您可以在开发过程中使用尽可能多的断言,而不会影响生产性能。
用断言进行调试
你可以通过调用assert(_:_:file:line:)
Swift标准库中的函数来编写断言。如果条件的结果是,则将此函数传递给计算结果为true
or 的表达式,false
并显示要显示的消息false
。例如:
let age = -3
assert(age >= 0, "A person's age can't be less than zero.")
// This assertion fails because -3 is not >= 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.")
}
执行先决条件
当条件有可能是错误的时候使用前提条件,但是对于代码继续执行肯定是正确的。例如,使用前提条件来检查下标是否超出范围,或检查函数是否已传递有效值。
你通过调用precondition(_:_:file:line:)
函数来编写一个前提条件。如果条件的结果是,则将此函数传递给计算结果为true
or 的表达式,false
并显示要显示的消息false
。例如:
// In the implementation of a subscript...
precondition(index > 0, "Index must be greater than zero.")
您也可以调用该preconditionFailure(_:file:line:)
函数来指示发生了故障 - 例如,如果采取了开关的默认情况,但所有有效的输入数据都应由交换机的其他情况之一处理。
注意
如果以非检查模式编译(-Ounchecked
),则不检查前置条件。编译器假定前置条件总是正确的,并相应地优化了你的代码。但是,fatalError(_:file:line:)
无论优化设置如何,该函数都会暂停执行。
您可以fatalError(_:file:line:)
在原型开发和早期开发中使用该函数,通过编写fatalError("Unimplemented")
存根实现来创建尚未实现的功能的存根。由于致命错误永远不会被优化,与断言或前提条件不同,您可以确保执行始终停止,如果遇到存根实现。
(原文地址) https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-ID309