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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM