zoukankan      html  css  js  c++  java
  • Swift5.3 语言指南(三) 快速预览

    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
    ➤微信公众号:山青咏芝(shanqingyongzhi)
    ➤博客园地址:山青咏芝(https://www.cnblogs.com/strengthen/
    ➤GitHub地址:https://github.com/strengthen/LeetCode
    ➤原文地址:https://www.cnblogs.com/strengthen/p/9711470.html 
    ➤如果链接不是山青咏芝的博客园地址,则可能是爬取作者的文章。
    ➤原文已修改更新!强烈建议点击原文地址阅读!支持作者!支持原创!
    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★

    传统建议使用新语言的第一个程序应打印“ Hello,world!”字样。屏幕上。在Swift中,这可以单行完成:

    1. print("Hello, world!")
    2. // Prints "Hello, world!"

    如果您使用C或Objective-C编写代码,则此语法看起来很熟悉-在Swift中,这行代码是完整的程序。您无需导入单独的库即可实现输入/输出或字符串处理等功能。在全局范围内编写的代码用作程序的入口点,因此您不需要main()功能。您也不需要在每个语句的末尾写分号。

    本教程通过向您展示如何完成各种编程任务,为您提供了足够的信息来开始在Swift中编写代码。如果您不了解某些内容,请不要担心,本教程的其余部分将详细介绍本教程中介绍的所有内容。

    简单的价值观

    使用let做一个常数,var使一个变量。常量的值不需要在编译时就知道,但是您必须为它赋值一次。这意味着您可以使用常量来命名一次确定但在许多地方使用的值。

    1. var myVariable = 42
    2. myVariable = 50
    3. let myConstant = 42

    常量或变量的类型必须与要分配给它的值的类型相同。但是,您不必总是显式地编写类型。在创建常量或变量时提供一个值,可使编译器推断其类型。在上面的示例中,编译器将其推断myVariable为整数,因为其初始值为整数。

    如果初始值不能提供足够的信息(或者没有初始值),请通过在变量后写一个类型(用冒号分隔)来指定类型。

    1. let implicitInteger = 70
    2. let implicitDouble = 70.0
    3. let explicitDouble: Double = 70

    实验

    创建一个显式类型为Float且值为的常数4

    值永远不会隐式转换为另一种类型。如果需要将值转换为其他类型,请显式创建所需类型的实例。

    1. let label = "The width is "
    2. let width = 94
    3. let widthLabel = label + String(width)

    实验

    尝试String从最后一行删除到的转换你得到什么错误?

    有一种甚至更简单的方法可以在字符串中包含值:在括号中写值,并在括号写反斜杠()。例如:

    1. let apples = 3
    2. let oranges = 5
    3. let appleSummary = "I have (apples) apples."
    4. let fruitSummary = "I have (apples + oranges) pieces of fruit."

    实验

    用于()在字符串中包含浮点计算,并在问候语中包含某人的姓名。

    """对于占用多行的字符串,请使用三个双引号()。只要每个引用行的缩进都与右引号的缩进匹配,就将其删除。例如:

    1. let quotation = """
    2. I said "I have (apples) apples."
    3. And then I said "I have (apples + oranges) pieces of fruit."
    4. """

    使用方括号([]创建数组和字典,并通过在方括号中写入索引或键来访问其元素。最后一个元素后允许使用逗号。

    1. var shoppingList = ["catfish", "water", "tulips"]
    2. shoppingList[1] = "bottle of water"
    3. var occupations = [
    4. "Malcolm": "Captain",
    5. "Kaylee": "Mechanic",
    6. ]
    7. occupations["Jayne"] = "Public Relations"

    数组随着添加元素而自动增长。

    1. shoppingList.append("blue paint")
    2. print(shoppingList)

    要创建一个空数组或字典,请使用初始化程序语法。

    1. let emptyArray = [String]()
    2. let emptyDictionary = [String: Float]()

    如果可以推断类型信息,则可以将空数组写为[],将空字典写为[:]例如,当您为变量设置新值或将参数传递给函数时。

    1. shoppingList = []
    2. occupations = [:]

    控制流

    使用ifswitch制作条件语句和使用forinwhilerepeatwhile进行循环。条件或循环变量的括号是可选的。身体周围需要支撑。

    1. let individualScores = [75, 43, 103, 87, 12]
    2. var teamScore = 0
    3. for score in individualScores {
    4. if score > 50 {
    5. teamScore += 3
    6. } else {
    7. teamScore += 1
    8. }
    9. }
    10. print(teamScore)
    11. // Prints "11"

    在一条if语句中,条件必须是布尔表达式-这意味着诸如之类的代码是错误,而不是与零的隐式比较。if score ... }

    您可以使用iflet一起使用可能缺少的值。这些值表示为可选值。可选值包含一个值或包含nil一个指示值丢失的值。?在值的类型后写一个问号(),以将该值标记为可选。

    1. var optionalString: String? = "Hello"
    2. print(optionalString == nil)
    3. // Prints "false"
    4. var optionalName: String? = "John Appleseed"
    5. var greeting = "Hello!"
    6. if let name = optionalName {
    7. greeting = "Hello, (name)"
    8. }

    实验

    更改optionalNamenil你得到什么问候?添加一个else设置为optionalNameis 的其他问候语子句nil

    如果可选值为nil,则条件为,false并且括号中的代码将被跳过。否则,将解压缩可选值,并将其分配给之后的常量let,这将使解压缩后的值在代码块内可用。

    处理可选值的另一种方法是使用??运算符提供默认值如果缺少可选值,则使用默认值。

    1. let nickname: String? = nil
    2. let fullName: String = "John Appleseed"
    3. let informalGreeting = "Hi (nickname ?? fullName)"

    开关支持任何类型的数据和各种比较操作-它们不限于整数和相等性测试。

    1. let vegetable = "red pepper"
    2. switch vegetable {
    3. case "celery":
    4. print("Add some raisins and make ants on a log.")
    5. case "cucumber", "watercress":
    6. print("That would make a good tea sandwich.")
    7. case let x where x.hasSuffix("pepper"):
    8. print("Is it a spicy (x)?")
    9. default:
    10. print("Everything tastes good in soup.")
    11. }
    12. // Prints "Is it a spicy red pepper?"

    实验

    尝试删除默认情况。你得到什么错误?

    注意如何let在模式中使用它来将与模式匹配的值分配给常量。

    在匹配的switch case中执行代码后,程序将从switch语句退出。执行不会继续到下一个案例,因此无需在每个案例代码的末尾显式地退出开关。

    您可以使用forin通过为每个键值对提供一对名称来迭代字典中的项目。字典是无序集合,因此它们的键和值以任意顺序进行迭代。

    1. let interestingNumbers = [
    2. "Prime": [2, 3, 5, 7, 11, 13],
    3. "Fibonacci": [1, 1, 2, 3, 5, 8],
    4. "Square": [1, 4, 9, 16, 25],
    5. ]
    6. var largest = 0
    7. for (kind, numbers) in interestingNumbers {
    8. for number in numbers {
    9. if number > largest {
    10. largest = number
    11. }
    12. }
    13. }
    14. print(largest)
    15. // Prints "25"

    实验

    添加另一个变量以跟踪最大数量的数字以及最大数量的数字。

    使用while重复的代码块,直到病情变化。循环的条件可以在末尾,以确保循环至少运行一次。

    1. var n = 2
    2. while n < 100 {
    3. n *= 2
    4. }
    5. print(n)
    6. // Prints "128"
    7. var m = 2
    8. repeat {
    9. m *= 2
    10. } while m < 100
    11. print(m)
    12. // Prints "128"

    您可以通过使用..<创建一系列索引来使索引保持循环

    1. var total = 0
    2. for i in 0..<4 {
    3. total += i
    4. }
    5. print(total)
    6. // Prints "6"

    使用..<做出各种省略了其上限值和使用...,使既包括值的范围。

    功能和关闭

    使用func声明函数。通过在函数名称后加上括号中的参数列表来调用该函数。使用->的参数名称和类型从函数的返回类型分开。

    1. func greet(person: String, day: String) -> String {
    2. return "Hello (person), today is (day)."
    3. }
    4. greet(person: "Bob", day: "Tuesday")

    实验

    删除day参数。添加一个参数以在问候语中包括今天的特色午餐。

    默认情况下,函数使用其参数名称作为其参数的标签。在参数名称前写一个自定义参数标签,或写_为不使用任何参数标签。

    1. func greet(_ person: String, on day: String) -> String {
    2. return "Hello (person), today is (day)."
    3. }
    4. greet("John", on: "Wednesday")

    使用元组生成复合值,例如,从函数返回多个值。元组的元素可以通过名称或数字来引用。

    1. func calculateStatistics(scores: [Int]) -> (min: Int, max: Int, sum: Int) {
    2. var min = scores[0]
    3. var max = scores[0]
    4. var sum = 0
    5. for score in scores {
    6. if score > max {
    7. max = score
    8. } else if score < min {
    9. min = score
    10. }
    11. sum += score
    12. }
    13. return (min, max, sum)
    14. }
    15. let statistics = calculateStatistics(scores: [5, 3, 100, 3, 9])
    16. print(statistics.sum)
    17. // Prints "120"
    18. print(statistics.2)
    19. // Prints "120"

    函数可以嵌套。嵌套函数可以访问在外部函数中声明的变量。您可以使用嵌套函数将代码组织为长函数或复杂函数。

    1. func returnFifteen() -> Int {
    2. var y = 10
    3. func add() {
    4. y += 5
    5. }
    6. add()
    7. return y
    8. }
    9. returnFifteen()

    函数是一流的类型。这意味着一个函数可以返回另一个函数作为其值。

    1. func makeIncrementer() -> ((Int) -> Int) {
    2. func addOne(number: Int) -> Int {
    3. return 1 + number
    4. }
    5. return addOne
    6. }
    7. var increment = makeIncrementer()
    8. increment(7)

    一个函数可以将另一个函数作为其参数之一。

    1. func hasAnyMatches(list: [Int], condition: (Int) -> Bool) -> Bool {
    2. for item in list {
    3. if condition(item) {
    4. return true
    5. }
    6. }
    7. return false
    8. }
    9. func lessThanTen(number: Int) -> Bool {
    10. return number < 10
    11. }
    12. var numbers = [20, 19, 7, 12]
    13. hasAnyMatches(list: numbers, condition: lessThanTen)

    函数实际上是闭包的一种特殊情况:可以稍后调用的代码块。闭包中的代码可以访问在创建闭包的作用域中可用的变量和函数,即使该闭包在执行时位于不同的作用域中—您已经看到了嵌套函数的示例。您可以使用大括号({})将代码括起来,从而编写一个没有名称的闭包使用in的参数和返回类型从身体分离。

    1. numbers.map({ (number: Int) -> Int in
    2. let result = 3 * number
    3. return result
    4. })

    实验

    重写闭包以对所有奇数返回零。

    您有几种选择可以更简洁地编写闭包。当已知闭包的类型(例如委托的回调)时,可以省略其参数的类型,返回类型或两者。单条语句闭包隐式返回其唯一语句的值。

    1. let mappedNumbers = numbers.map({ number in 3 * number })
    2. print(mappedNumbers)
    3. // Prints "[60, 57, 21, 36]"

    您可以通过数字而不是名称来引用参数-这种方法在很短的闭包中特别有用。作为最后一个参数传递给函数的闭包可以在括号后立即显示。如果闭包是函数的唯一参数,则可以完全省略括号。

    1. let sortedNumbers = numbers.sorted { $0 > $1 }
    2. print(sortedNumbers)
    3. // Prints "[20, 19, 12, 7]"

    对象和类

    使用class后跟类的名称来创建一个类。类中的属性声明与常量或变量声明的编写方式相同,只不过它是在类的上下文中编写的。同样,方法和函数声明的编写方式相同。

    1. class Shape {
    2. var numberOfSides = 0
    3. func simpleDescription() -> String {
    4. return "A shape with (numberOfSides) sides."
    5. }
    6. }

    实验

    用添加一个常量属性let,并添加另一个带有参数的方法。

    通过在类名称后加上括号来创建类的实例。使用点语法访问实例的属性和方法。

    1. var shape = Shape()
    2. shape.numberOfSides = 7
    3. var shapeDescription = shape.simpleDescription()

    Shape该类的版本缺少重要的内容:创建实例时用于设置类的初始化程序。使用init创建一个。

    1. class NamedShape {
    2. var numberOfSides: Int = 0
    3. var name: String
    4. init(name: String) {
    5. self.name = name
    6. }
    7. func simpleDescription() -> String {
    8. return "A shape with (numberOfSides) sides."
    9. }
    10. }

    注意如何self使用name属性来区分属性和name初始化程序参数。创建类的实例时,初始化函数的参数像函数调用一样传递。每个属性都需要在其声明中(如numberOfSides)或在初始化程序中(如name分配一个值

    deinit如果需要在释放对象之前执行一些清理,请使用来创建一个反初始化程序。

    子类在其类名之后包括其超类名,并用冒号分隔。不需要类继承任何标准根类,因此您可以根据需要包含或忽略超类。

    覆盖超类的实现的子类上override的方法标记为—偶然覆盖方法,不带override,编译器将其检测为错误。编译器还会检测override那些实际上没有覆盖超类中任何方法的方法。

    1. class Square: NamedShape {
    2. var sideLength: Double
    3. init(sideLength: Double, name: String) {
    4. self.sideLength = sideLength
    5. super.init(name: name)
    6. numberOfSides = 4
    7. }
    8. func area() -> Double {
    9. return sideLength * sideLength
    10. }
    11. override func simpleDescription() -> String {
    12. return "A square with sides of length (sideLength)."
    13. }
    14. }
    15. let test = Square(sideLength: 5.2, name: "my test square")
    16. test.area()
    17. test.simpleDescription()

    实验

    再创建一个NamedShape名为的子类,Circle它以半径和名称作为其初始值设定项的参数。实现area()simpleDescription()方法Circle

    除了存储的简单属性外,属性还可以具有getter和setter。

    1. class EquilateralTriangle: NamedShape {
    2. var sideLength: Double = 0.0
    3. init(sideLength: Double, name: String) {
    4. self.sideLength = sideLength
    5. super.init(name: name)
    6. numberOfSides = 3
    7. }
    8. var perimeter: Double {
    9. get {
    10. return 3.0 * sideLength
    11. }
    12. set {
    13. sideLength = newValue / 3.0
    14. }
    15. }
    16. override func simpleDescription() -> String {
    17. return "An equilateral triangle with sides of length (sideLength)."
    18. }
    19. }
    20. var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle")
    21. print(triangle.perimeter)
    22. // Prints "9.3"
    23. triangle.perimeter = 9.9
    24. print(triangle.sideLength)
    25. // Prints "3.3000000000000003"

    在for的setter中perimeter,新值具有隐式名称newValue您可以在后面的括号中提供一个明确的名称set

    请注意,EquilateralTriangle该类的初始化程序具有三个不同的步骤:

    1. 设置子类声明的属性的值。
    2. 调用超类的初始化程序。
    3. 更改超类定义的属性的值。此时还可以完成使用方法,getter或setter的任何其他设置工作。

    如果您不需要计算属性,但仍然需要提供在设置新值之前和之后运行的代码,请使用willSetdidSet只要提供的代码在初始化程序之外更改,就可以运行您提供的代码。例如,下面的类确保其三角形的边长始终与其正方形的边长相同。

    1. class TriangleAndSquare {
    2. var triangle: EquilateralTriangle {
    3. willSet {
    4. square.sideLength = newValue.sideLength
    5. }
    6. }
    7. var square: Square {
    8. willSet {
    9. triangle.sideLength = newValue.sideLength
    10. }
    11. }
    12. init(size: Double, name: String) {
    13. square = Square(sideLength: size, name: name)
    14. triangle = EquilateralTriangle(sideLength: size, name: name)
    15. }
    16. }
    17. var triangleAndSquare = TriangleAndSquare(size: 10, name: "another test shape")
    18. print(triangleAndSquare.square.sideLength)
    19. // Prints "10.0"
    20. print(triangleAndSquare.triangle.sideLength)
    21. // Prints "10.0"
    22. triangleAndSquare.square = Square(sideLength: 50, name: "larger square")
    23. print(triangleAndSquare.triangle.sideLength)
    24. // Prints "50.0"

    使用可选值时,可以?在方法,属性和下标之类的操作之前编写如果之前的值?nil,则后面的一切都会?被忽略,整个表达式的值是nil否则,将取消包装可选值,并且所有操作之后的内容都将?被包装。在这两种情况下,整个表达式的值都是一个可选值。

    1. let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square")
    2. let sideLength = optionalSquare?.sideLength

    枚举和结构

    使用enum创建一个枚举。像类和所有其他命名类型一样,枚举可以具有与之关联的方法。

    1. enum Rank: Int {
    2. case ace = 1
    3. case two, three, four, five, six, seven, eight, nine, ten
    4. case jack, queen, king
    5. func simpleDescription() -> String {
    6. switch self {
    7. case .ace:
    8. return "ace"
    9. case .jack:
    10. return "jack"
    11. case .queen:
    12. return "queen"
    13. case .king:
    14. return "king"
    15. default:
    16. return String(self.rawValue)
    17. }
    18. }
    19. }
    20. let ace = Rank.ace
    21. let aceRawValue = ace.rawValue

    实验

    编写一个通过比较两个Rank原始值来比较两个值的函数。

    默认情况下,Swift分配的原始值从零开始,每次递增1,但是您可以通过显式指定值来更改此行为。在上面的示例中,Ace显式指定了的原始值1,其余原始值按顺序分配。您还可以使用字符串或浮点数作为枚举的原始类型。使用该rawValue属性访问枚举案例的原始值。

    使用init?(rawValue:)初始化程序从原始值创建枚举的实例。它返回任一枚举的情况下的匹配的原始值或nil如果不存在匹配Rank

    1. if let convertedRank = Rank(rawValue: 3) {
    2. let threeDescription = convertedRank.simpleDescription()
    3. }

    枚举的大小写值是实际值,而不仅仅是写原始值的另一种方法。实际上,在没有有意义的原始价值的情况下,您不必提供原始价值。

    1. enum Suit {
    2. case spades, hearts, diamonds, clubs
    3. func simpleDescription() -> String {
    4. switch self {
    5. case .spades:
    6. return "spades"
    7. case .hearts:
    8. return "hearts"
    9. case .diamonds:
    10. return "diamonds"
    11. case .clubs:
    12. return "clubs"
    13. }
    14. }
    15. }
    16. let hearts = Suit.hearts
    17. let heartsDescription = hearts.simpleDescription()

    实验

    添加一个color()方法Suit,对于黑桃和球棒返回“黑色”,对于心形和菱形返回“红色”。

    请注意hearts上面引用枚举大小写的两种方式:为hearts常量分配值时,枚举大小写Suit.hearts以其全名引用,因为常量没有指定显式类型。在交换机内部,枚举用缩写形式表示,.hearts因为self已知的值是合适的。只要知道值的类型,就可以使用缩写形式。

    如果枚举具有原始值,则将这些值确定为声明的一部分,这意味着特定枚举用例的每个实例始终具有相同的原始值。枚举用例的另一种选择是具有与用例关联的值-这些值是在创建实例时确定的,并且对于枚举用例的每个实例而言,它们可能是不同的。您可以将关联的值视为枚举案例实例的存储属性。例如,考虑从服务器请求日出和日落时间的情况。服务器要么以请求的信息作为响应,要么以错误的描述作为响应。

    1. enum ServerResponse {
    2. case result(String, String)
    3. case failure(String)
    4. }
    5. let success = ServerResponse.result("6:00 am", "8:09 pm")
    6. let failure = ServerResponse.failure("Out of cheese.")
    7. switch success {
    8. case let .result(sunrise, sunset):
    9. print("Sunrise is at (sunrise) and sunset is at (sunset).")
    10. case let .failure(message):
    11. print("Failure... (message)")
    12. }
    13. // Prints "Sunrise is at 6:00 am and sunset is at 8:09 pm."

    实验

    ServerResponse在交换机和交换机之间添加第三种情况

    请注意,如何将ServerResponse从日出时间和日落时间中提取出来,作为将值与转换案例进行匹配的一部分。

    使用struct创建的结构。结构支持许多与类相同的行为,包括方法和初始化程序。结构和类之间最重要的区别之一是,结构在代码中传递时始终会被复制,而类是通过引用传递的。

    1. struct Card {
    2. var rank: Rank
    3. var suit: Suit
    4. func simpleDescription() -> String {
    5. return "The (rank.simpleDescription()) of (suit.simpleDescription())"
    6. }
    7. }
    8. let threeOfSpades = Card(rank: .three, suit: .spades)
    9. let threeOfSpadesDescription = threeOfSpades.simpleDescription()

    实验

    编写一个函数,该函数返回一个包含一整套纸牌的数组,每个纸牌的等级和西装组合各一张。

    协议和扩展

    使用protocol申报的协议。

    1. protocol ExampleProtocol {
    2. var simpleDescription: String { get }
    3. mutating func adjust()
    4. }

    类,枚举和结构都可以采用协议。

    1. class SimpleClass: ExampleProtocol {
    2. var simpleDescription: String = "A very simple class."
    3. var anotherProperty: Int = 69105
    4. func adjust() {
    5. simpleDescription += " Now 100% adjusted."
    6. }
    7. }
    8. var a = SimpleClass()
    9. a.adjust()
    10. let aDescription = a.simpleDescription
    11. struct SimpleStructure: ExampleProtocol {
    12. var simpleDescription: String = "A simple structure"
    13. mutating func adjust() {
    14. simpleDescription += " (adjusted)"
    15. }
    16. }
    17. var b = SimpleStructure()
    18. b.adjust()
    19. let bDescription = b.simpleDescription

    实验

    向添加新的要求ExampleProtocol你需要什么样的变化做出SimpleClassSimpleStructure使他们仍然符合协议?

    请注意,mutating在的声明中使用了关键字SimpleStructure来标记修改结构的方法。的声明SimpleClass不需要其任何标记为变异的方法,因为类上的方法始终可以修改该类。

    用于extension向现有类型添加功能,例如新方法和计算属性。您可以使用扩展将协议一致性添加到在其他地方声明的类型,甚至添加到从库或框架导入的类型。

    1. extension Int: ExampleProtocol {
    2. var simpleDescription: String {
    3. return "The number (self)"
    4. }
    5. mutating func adjust() {
    6. self += 42
    7. }
    8. }
    9. print(7.simpleDescription)
    10. // Prints "The number 7"

    实验

    Double添加absoluteValue属性类型编写扩展名

    您可以像使用任何其他命名类型一样使用协议名称,例如,创建具有不同类型但都符合一个协议的对象的集合。当使用类型为协议类型的值时,协议定义之外的方法不可用。

    1. let protocolValue: ExampleProtocol = a
    2. print(protocolValue.simpleDescription)
    3. // Prints "A very simple class. Now 100% adjusted."
    4. // print(protocolValue.anotherProperty) // Uncomment to see the error

    即使变量protocolValue的运行时类型为SimpleClass,编译器也将其视为的给定类型ExampleProtocol这意味着除了协议一致性之外,您不能意外访问该类实现的方法或属性。

    错误处理

    您可以使用采用该Error协议的任何类型来表示错误

    1. enum PrinterError: Error {
    2. case outOfPaper
    3. case noToner
    4. case onFire
    5. }

    使用throw抛出一个错误,并throws标记,可以抛出一个错误的功能。如果在函数中引发错误,则该函数将立即返回,并且调用该函数的代码将处理该错误。

    1. func send(job: Int, toPrinter printerName: String) throws -> String {
    2. if printerName == "Never Has Toner" {
    3. throw PrinterError.noToner
    4. }
    5. return "Job sent"
    6. }

    有几种处理错误的方法。一种方法是使用docatch在该do内部,您可以标记可能会通过try在其前面写入引发错误的代码catch块内,错误会自动命名,error除非您给它改了名称。

    1. do {
    2. let printerResponse = try send(job: 1040, toPrinter: "Bi Sheng")
    3. print(printerResponse)
    4. } catch {
    5. print(error)
    6. }
    7. // Prints "Job sent"

    实验

    将打印机名称更改为,以便该函数引发错误。"Never Has Toner"send(job:toPrinter:)

    您可以提供多个catch处理特定错误的块。catch就像case在切换之后一样,编写了一个模式

    1. do {
    2. let printerResponse = try send(job: 1440, toPrinter: "Gutenberg")
    3. print(printerResponse)
    4. } catch PrinterError.onFire {
    5. print("I'll just put this over here, with the rest of the fire.")
    6. } catch let printerError as PrinterError {
    7. print("Printer error: (printerError).")
    8. } catch {
    9. print(error)
    10. }
    11. // Prints "Job sent"

    实验

    添加代码以在do内引发错误您需要引发哪种错误,以便第一个catch处理该错误那第二块和第三块呢?

    处理错误的另一种方法是try?用于将结果转换为可选的。如果函数抛出错误,则将丢弃特定错误,结果为nil否则,结果是一个可选值,其中包含函数返回的值。

    1. let printerSuccess = try? send(job: 1884, toPrinter: "Mergenthaler")
    2. let printerFailure = try? send(job: 1885, toPrinter: "Never Has Toner")

    defer写的是在函数中的所有其它代码后执行代码块,只是在函数返回之前。无论函数是否引发错误,都将执行代码。defer即使需要在不同的时间执行设置和清除代码,也可以使用它们彼此相邻。

    1. var fridgeIsOpen = false
    2. let fridgeContent = ["milk", "eggs", "leftovers"]
    3. func fridgeContains(_ food: String) -> Bool {
    4. fridgeIsOpen = true
    5. defer {
    6. fridgeIsOpen = false
    7. }
    8. let result = fridgeContent.contains(food)
    9. return result
    10. }
    11. fridgeContains("banana")
    12. print(fridgeIsOpen)
    13. // Prints "false"

    泛型

    在尖括号内写一个名称,以构成通用函数或类型。

    1. func makeArray<Item>(repeating item: Item, numberOfTimes: Int) -> [Item] {
    2. var result = [Item]()
    3. for _ in 0..<numberOfTimes {
    4. result.append(item)
    5. }
    6. return result
    7. }
    8. makeArray(repeating: "knock", numberOfTimes: 4)

    您可以使函数和方法以及类,枚举和结构成为通用形式。

    1. // Reimplement the Swift standard library's optional type
    2. enum OptionalValue<Wrapped> {
    3. case none
    4. case some(Wrapped)
    5. }
    6. var possibleInteger: OptionalValue<Int> = .none
    7. possibleInteger = .some(100)

    where在正文前使用权利来指定需求列表,例如,要求类型实现协议,要求两个类型相同或要求一个类具有特定的超类。

    1. func anyCommonElements<T: Sequence, U: Sequence>(_ lhs: T, _ rhs: U) -> Bool
    2. where T.Element: Equatable, T.Element == U.Element
    3. {
    4. for lhsItem in lhs {
    5. for rhsItem in rhs {
    6. if lhsItem == rhsItem {
    7. return true
    8. }
    9. }
    10. }
    11. return false
    12. }
    13. anyCommonElements([1, 2, 3], [3])

    实验

    修改该anyCommonElements(_:_:)函数以使该函数返回任何两个序列共同具有的元素的数组。

    写作和写作一样<T: Equatable><T> ... where T: Equatable

  • 相关阅读:
    windows下nginx以服务自启动
    redis数据库可视化工具(RedisDesktopManager)
    myecplise中的svn如何切换账号
    oracle创建视图包含clob字段,报错:数据类型不一致:应为-,但却获得CLOB
    java.lang.UnsatisfiedLinkError: no jacob-1.18-x64 in java.library.path
    java中关于日期的处理
    js截取字符串
    关于sql developer中表或视图不存在以及查找日志窗口
    在html页面切换标题栏目时出现页面抖动
    严重: IOException while loading persisted sessions: java.io.EOFException
  • 原文地址:https://www.cnblogs.com/strengthen/p/9711470.html
Copyright © 2011-2022 走看看