SWIFT

SWIFT

計算機編程語言
Swift,蘋果于2014年WWDC蘋果開發者大會發布的新開發語言,可與Objective-C共同運行于macOS和iOS平台,用于搭建基于蘋果平台的應用程序。Swift是一款易學易用的編程語言,而且它還是第一套具有與腳本語言同樣的表現力和趣味性的系統編程語言。Swift的設計以安全為出發點,以避免各種常見的編程錯誤類别。 [1]2015年12月4日,蘋果公司宣布其Swift編程語言開放源代碼。長600多頁的The Swift Programming Language 可以在線免費下載。
  • 中文名:雨燕
  • 外文名:Swift
  • 别名:
  • 發布時間:2014年6月2日
  • 發行組織:Apple
  • 源 于:Objective-C
  • 系 統:macOS、iOS、linux等

發展曆史

2014-6-3 Swift于WWDC蘋果開發者大會發布。

2014-6-4 《Swift中文版》翻譯組在github上進行協同翻譯 。此項目開始不到一周就獲得了1067個star。該項目的發起人是北航的大三學生 。

2014-6-12《Swift中文版》第一版發布 。

2015年12月4日,蘋果公司宣布其Swift編程語言開放源代碼 。長600多頁的The Swift Programming Language 可以在線免費下載。同時可以在蘋果官方Github下載 。

2020年1月的TIOBE編程語言排行榜顯示,Swift從第15名上升至第9名。

應用範圍

Swift是一種新的編程語言,用于編寫iOS和macOS應用。Swift結合了C和Objective-C的優點并且不受C兼容性的限制。Swift采用安全的編程模式并添加了很多新特性,這将使編程更簡單,更靈活,也更有趣。Swift是基于成熟而且倍受喜愛的Cocoa和Cocoa Touch框架,他的降臨将重新定義軟件開發。

Swift的開發從很久之前就開始了。為了給Swift打好基礎,蘋果公司改進了編譯器,調試器和框架結構。我們使用自動引用計數(Automatic Reference Counting, ARC)來簡化内存管理。我們在Foundation和Cocoa的基礎上構建框架棧并将其标準化。Objective-C本身支持塊、集合語法和模塊,所以框架可以輕松支持現代編程語言技術。正是得益于這些基礎工作,我們才能發布這樣一個用于未來蘋果軟件開發的新語言。

Objective-C開發者對Swift并不會感到陌生。它采用了Objective-C的命名參數以及動态對象模型,可以無縫對接到現有的Cocoa框架,并且可以兼容Objective-C代碼。在此基礎之上,Swift還有許多新特性并且支持過程式編程和面向對象編程。

操作優點

Swift 對于初學者來說也很友好。它是第一個既滿足工業标準又像腳本語言一樣充滿表現力和趣味的編程語言。它支持代碼預覽,這個革命性的特性可以允許程序員在不編譯和運行應用程序的前提下運行Swift代碼并實時查看結果。

應用優勢

Swift将現代編程語言的精華和蘋果工程師文化的智慧結合了起來。編譯器對性能進行了優化,編程語言對開發進行了優化,兩者互不幹擾,魚與熊掌兼得。Swift 既可以用于開發“hello, world”這樣的小程序,也可以用于開發一套完整的操作系統。所有的這些特性讓 Swift對于開發者和蘋果來說都是一項值得的投資。

示例程序

Swift不需要引入頭文件或寫在main()内,也不需要在每一句加上分号(當然,若你保有使用某些其他語言的習慣,如Java、C等 加上分号結尾亦不會報錯)。

以下一行便是Hello,World程序 :

1tprint("Hello,world")

主要功能

語法簡便

Swift是編程語言的最新研究成果,并結合數十年的經驗建設蘋果平台的結果。結轉自Objective-C的命名參數表示在一個幹淨的語法,使得Swift的API更容易閱讀和維護。

推斷類型使代碼更幹淨,不易犯錯誤,而模塊消除了頭,并提供命名空間。内存自動管理,而你甚至都不需要輸入分号。

其他功能

Swift特有許多其他的功能,使你的代碼更傳神:

閉包的統一與函數指針

元組和多個返回值

泛型

快速而簡潔的叠代範圍或集合

支持的方法,擴展的協議結構。

函數式編程模式,例如:映射(map)和過濾器(filter)

互動遊樂

Swift Playgrounds使編寫語言代碼難以置信的簡單和有趣。輸入一行代碼,結果立即出現。如果您的代碼通過一個循環運行一段時間你可以看它在時間軸助理進展。在時間線中的圖表顯示變量,組成一個視圖時繪制每一步,并能起到一個動畫SpriteKit現場。當你在Playgrounds上完善你的代碼,隻需将代碼到您的項目。有了Playgrounds,您可以:

設計一種新的算法,看其工作的每一步

創建新的測試,驗證他們推動到您的測試套件前工作

嘗試新的API來磨練你的Swift的編碼技巧

REPL

閱讀-分析-打印環路(REPL):在Xcode調試控制台包括内建Swift使用語法來評估,并與正在運行的應用程序進行交互,或者編寫新的代碼,看看它是如何工作的一個類似腳本的環境Swift語言的交互式版本。可以從Xcode的控制台内,或在終端。

專為安全

Swift消除了不安全的代碼。變量總是初始化之前使用,數組和整數檢查溢出,内存自動管理。語法被調整到可以很容易地定義你的意圖 - 例如,簡單的三個字符的關鍵字定義一個變量(var)或常量(let)。

在Swift的安全模式被調整為強大的Cocoa和Cocoa Touch的API。認識和妥善處理其中的對象是零案件是基本的框架和Swift的代碼使這個非常容易。添加一個字符可以代替曾經Objective-C中整行的代碼。這一相互配合,使構建iOS和Mac應用程序比以前更加容易和安全。

高效強大

Swift是為高效而強大的編程而創建的語言。Swift采用了高性能的Apple LLVM編譯器,Swift代碼轉化為優化過的本地代碼,充分利用現代化的Mac,iPhone和iPad的硬件。語法和标準庫也非常簡潔,讓編程的流程大大縮短、簡化

Swift采用了C和Objective-C語言中的優秀成分。Swift也包括了很多其他語言的特征,如類型,流程控制和運算符。Swift還提供了面向對象的特性,如類與協議。

學習入門

Hello world

第一個程序應該在屏幕上打印“Hello, world”。在Swift中,可以用一行代碼實現:

print("Hello, world")

如果你寫過C或者Objective-C代碼,那你應該很熟悉這種形式——在Swift中,這行代碼就是一個完整的程序。你不需要為了輸入輸出或者字符串處理導入一個單獨的庫。全局作用域中的代碼會被自動當做程序的入口點,所以你也不需要main函數。你同樣不需要在每個語句結尾寫上分号。

這個教程會通過一系列編程例子來讓你對Swift有初步了解,如果你有什麼不理解的地方也不用擔心——任何本章介紹的内容都會在後面的章節中詳細講解。

注意:

為了獲得最好的體驗,在Xcode當中使用代碼預覽功能。代碼預覽功能可以讓你編輯代碼并實時看到運行結果。

簡單值

使用let來聲明常量,使用var來聲明變量。一個常量的值在編譯時并不需要獲取,但是你隻能為它賦值一次。也就是說你可以用常量來表示這樣一個值:你隻需要決定一次,但是需要使用很多次。

1

2

3

var myVariable = 42

    myVariable = 50

let myConstant = 42

常量或者變量的類型必須和你賦給它們的值一樣。然而,聲明時類型是可選的,聲明的同時賦值的話,編譯器會自動推斷類型。在上面的例子中,編譯器推斷出myVariable是一個整數(integer)因為它的初始值是整數。

如果初始值沒有提供足夠的信息(或者沒有初始值),那你需要在變量後面聲明類型,用冒号分割。

1

2

3

let implicitInteger = 70

let implicitDouble = 70.0

let explicitDouble: Double = 70

創建一個常量,顯式指定類型為Float并指定初始值為4。

值永遠不會被隐式轉換為其他類型。如果你需要把一個值轉換成其他類型,請顯式轉換。

1

2

3

let label = "The width is"

let width = 94

let widthLabel = label + String(width)

删除最後一行中的String,錯誤提示是什麼?

有一種更簡單的把值轉換成字符串的方法:把值寫到括号中,并且在括号之前寫一個反斜杠。例如:

1

2

3

4

let apples = 3

let oranges = 5

let appleSummary = "I have (apples) apples."

let fruitSummary = "I have (apples + oranges) pieces of fruit."

使用()來把一個浮點計算轉換成字符串,并加上某人的名字,和他打個招呼。

使用方括号[]來創建數組和字典,并使用下标或者鍵(key)來訪問元素。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

var shoppingList = ["catfish", "water", "tulips", "blue paint"]

    shoppingList[1] = "bottle of water"

// ["catfish", "bottle of water", "tulips", "blue paint"]

var occupations = [

    "Malcolm": "Captain",

    "Kaylee": "Mechanic",

]

    occupations["Jayne"] = "Public Relations"

/*

[

    "Malcolm": "Captain",

    "Kaylee": "Mechanic",

    "Jayne": "Public Relations",

]

*/

要創建一個空數組或者字典,使用初始化語法。

1

2

let emptyArray = [String]()

let emptyDictionary = Dictionary()

如果類型信息可以被推斷出來,你可以用[]和[:]來創建空數組和空字典——就像你聲明變量或者給函數傳參數的時候一樣。

1

    shoppingList = [] // 去逛街并買點東西

控制流

使用if和switch來進行條件操作,使用for-in、for、while和do-while來進行循環。包裹條件和循環變量括号可以省略,但是語句體的大括号是必須的。

1

2

3

4

5

6

7

8

9

10

11

let individualScores = [75, 43, 103, 87, 12]

var teamScore = 0

for score in individualScores {

    if score > 50 {

        teamScore += 3

    } else {

        teamScore += 1

    }

}

print(teamScore) 

//11

在if語句中,條件必須是一個布爾表達式——這意味着像if score { ... }這樣的代碼将報錯,而不會隐形地與 0 做對比。

你可以一起使用if和let來處理值缺失的情況。有些變量的值是可選的。一個可選的值可能是一個具體的值或者是nil,表示值缺失。在類型後面加一個問号來标記這個變量的值是可選的。

1

2

3

4

5

6

7

var optionalString: String? = "Hello"

    optionalString == nil // false

var optionalName: String? = "John Appleseed"

var greeting = "Hello!"

if let name = optionalName {

    greeting = "Hello, (name)" //Hello, John Appleseed

把optionalName改成nil,greeting會是什麼?添加一個else語句,當optionalName是nil時給greeting賦一個不同的值。

如果變量的可選值是nil,條件會判斷為false,大括号中的代碼會被跳過。如果不是nil,會将值賦給let後面的常量,這樣代碼塊中就可以使用這個值了。

switch支持任意類型的數據以及各種比較操作——不僅僅是整數以及測試相等。

1

2

3

4

5

6

7

8

9

10

11

let vegetable = "red pepper"

switch vegetable {

    case "celery":

        let vegetableComment = "Add some raisins and make ants on a log."

    case "cucumber", "watercress":

        let vegetableComment = "That would make a good tea sandwich."

    case let x where x.hasSuffix("pepper"):

        let vegetableComment = "Is it a spicy (x)?"

    default:

        let vegetableComment = "Everything tastes good in soup."

}

删除default語句,看看會有什麼錯誤?

運行switch中匹配到的子句之後,程序會退出switch語句,并不會繼續向下運行,所以不需要在每個子句結尾寫break。

你可以使用for-in來遍曆字典,需要兩個變量來表示每個鍵值對。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

let interestingNumbers = [

    "Prime": [2, 3, 5, 7, 11, 13],

    "Fibonacci": [1, 1, 2, 3, 5, 8],

    "Square": [1, 4, 9, 16, 25],

]

var largest = 0

for (kind, numbers) in interestingNumbers {

    for number in numbers {

        if number > largest {

            largest = number

        }

    }

}

print(largest)

添加另一個變量來記錄哪種類型的數字是最大的。

使用while來重複運行一段代碼直到不滿足條件。循環條件可以在開頭也可以在結尾。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

var n = 2

while n < 100 {

    n = n * 2

}

print(n)

var m = 2

repeat {

    m = m * 2

} while m < 100

print(m)

// 你可以在循環中使用..<來表示範圍:[0, 1, 2]

var firstForLoop = 0

for i in 0..<3 {

    firstForLoop += i

}

print(firstForLoop)

使用..<創建的範圍不包含上界,如果想包含的話需要使用...。

函數閉包

使用func來聲明一個函數,使用名字和參數來調用函數。使用->來指定函數返回值。

1

2

3

4

func greet(name: String, day: String) -> String {

    return "Hello (name), today is (day)."

}

greet(name: "Bob", day: "Tuesday")

删除day參數,添加一個參數來表示今天吃了什麼午飯。

使用一個元組來返回多個值。

1

2

3

4

func getGasPrices() -> (Double, Double, Double) {

    return (3.59, 3.69, 3.79)

}

getGasPrices()

函數可以帶有可變個數的參數,這些參數在函數内表現為數組的形式:

1

2

3

4

5

6

7

8

9

func sumOf(numbers: Int...) -> Int {

    var sum = 0

    for number in numbers {

        sum += number

    }

    return sum

}

sumOf() // 0

sumOf(numbers:42, 597, 12) // 651

函數可以嵌套。被嵌套的函數可以訪問外側函數的變量,你可以使用嵌套函數來重構一個太長或者太複雜的函數。

1

2

3

4

5

6

7

8

9

func returnFifteen() -> Int {

    var y = 10

    func add() {

        y += 5

    }

    add()

    return y

}

returnFifteen() // 15

函數是第一等類型,這意味着函數可以作為另一個函數的返回值。

1

2

3

4

5

6

7

8

func makeIncrementer() -> ((Int) -> Int) {

    func addOne(number: Int) -> Int {

        return 1 + number

    }

    return addOne

}

var increment = makeIncrementer()

increment(7) // 8

函數也可以當做參數傳入另一個函數。

1

2

3

4

5

6

7

8

9

10

11

12

13

func hasAnyMatches(list: [Int], condition: (Int) -> Bool) -> Bool {

    for item in list {

        if condition(item) {

            return true

        }

    }

    return false

}

func lessThanTen(number: Int) -> Bool {

    return number < 10

}

var numbers = [20, 19, 7, 12]

hasAnyMatches(list: numbers, condition: lessThanTen)

函數實際上是一種特殊的閉包,你可以使用{}來創建一個匿名閉包。使用in将參數和返回值類型聲明與閉包函數體進行分離。

1

2

3

4

5

numbers.map({

    (number: Int) -> Int in

        let result = 3 * number

    return result

})

有很多種創建閉包的方法。如果一個閉包的類型已知,比如作為一個回調函數,你可以忽略參數的類型和返回值。單個語句閉包會把它語句的值當做結果返回。

1

numbers.map({ number in 3 * number })

你可以通過參數位置而不是參數名字來引用參數——這個方法在非常短的閉包中非常有用。當一個閉包作為最後一個參數傳給一個函數的時候,它可以直接跟在括号後面。

1

sort([1, 5, 3, 12, 2]) { $0 > $1 }

對象和類

使用class和類名來創建一個類。類中屬性的聲明和常量、變量聲明一樣,唯一的區别就是它們的上下文是類。同樣,方法和函數聲明也一樣。

1

2

3

4

5

6

class Shape {

    var numberOfSides = 0

    func simpleDescription() -> String {

        return "A shape with (numberOfSides) sides."

    }

}

要創建一個類的實例,在類名後面加上括号。使用點語法來訪問實例的屬性和方法。

1

2

3

var shape = Shape()

    shape.numberOfSides = 7

var shapeDescription = shape.simpleDescription()

這個版本的Shape類缺少了一些重要的東西:一個構造函數來初始化類實例。使用init來創建一個構造器。

1

2

3

4

5

6

7

8

9

10

class NamedShape {

    var numberOfSides: Int = 0

    var name: String

    init(name: String) {

        self.name = name

    }

    func simpleDescription() -> String {

        return "A shape with (numberOfSides) sides."

    }

}

注意self被用來區别實例變量。當你創建實例的時候,像傳入函數參數一樣給類傳入構造器的參數。每個屬性都需要賦值——無論是通過聲明(就像numberOfSides)還是通過構造器(就像name)。如果你需要在删除對象之前進行一些清理工作,使用deinit創建一個析構函數。子類的定義方法是在它們的類名後面加上父類的名字,用冒号分割。創建類的時候并不需要一個标準的根類,所以你可以忽略父類。

子類如果要重寫父類的方法的話,需要用override标記——如果沒有添加override就重寫父類方法的話編譯器會報錯。編譯器同樣會檢測override标記的方法是否确實在父類中。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

class Square: NamedShape {

    var sideLength: Double

    init(sideLength: Double, name: String) {

        self.sideLength = sideLength

        super.init(name: name)

        numberOfSides = 4

    }

    func area() -> Double {

        return sideLength * sideLength

    }

    override func simpleDescription() -> String {

        return "A square with sides of length (sideLength)."

    }

}

let test = Square(sideLength: 5.2, name: "my test square")

test.area()

test.simpleDescription()

創建NamedShape的另一個子類Circle,構造器接收兩個參數,一個是半徑一個是名稱,實現area和describe方法。

屬性可以有 getter 和 setter 。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

class EquilateralTriangle: NamedShape {

    var sideLength: Double = 0.0

    init(sideLength: Double, name: String) {

        self.sideLength = sideLength

        super.init(name: name)

        numberOfSides = 3

    }

    var perimeter: Double {

        get {

            return 3.0 * sideLength

        }

        set {

            sideLength = newValue / 3.0

        }

    }

    override func simpleDescription() -> String {

        return "An equilateral triagle with sides of length (sideLength)."

    }

}

var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle")

print(triangle.perimeter)

triangle.perimeter = 9.9

print(triangle.sideLength)

在perimeter的 setter 中,新值的名字是newValue。你可以在set之後顯式的設置一個名字。

注意EquilateralTriangle類的構造器執行了三步:

設置子類聲明的屬性值

調用父類的構造器

改變父類定義的屬性值。其他的工作比如調用方法、getters和setters也可以在這個階段完成。

如果你不需要計算屬性但是需要在設置一個新值之前運行一些代碼,使用willSet和didSet。

比如,下面的類确保三角形的邊長總是和正方形的邊長相同。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

class TriangleAndSquare {

    var triangle: EquilateralTriangle {

        willSet {

            square.sideLength = newValue.sideLength

        }

    }

    var square: Square {

        willSet {

            triangle.sideLength = newValue.sideLength

        }

    }

    init(size: Double, name: String) {

        square = Square(sideLength: size, name: name)

        triangle = EquilateralTriangle(sideLength: size, name: name)

    }

}

var triangleAndSquare = TriangleAndSquare(size: 10, name: "another test shape")

pirnt(triangleAndSquare.square.sideLength)

print(triangleAndSquare.triangle.sideLength)

triangleAndSquare.square = Square(sideLength: 50, name: "larger square")

print(triangleAndSquare.triangle.sideLength)

類中的方法和一般的函數有一個重要的區别,函數的參數名隻在函數内部使用,但是方法的參數名需要在調用的時候顯式說明(除了第一個參數)。默認情況下,方法的參數名和它在方法内部的名字一樣,不過你也可以定義第二個名字,這個名字被用在方法内部。

1

2

3

4

5

6

7

8

class Counter {

    var count: Int = 0

    func incrementBy(amount: Int, numberOfTimes times: Int) {

        count += amount * times

    }

}

var counter = Counter()

counter.incrementBy(2, numberOfTimes: 7)

處理變量的可選值時,你可以在操作(比如方法、屬性和子腳本)之前加?。如果?之前的值是nil,?後面的東西都會被忽略,并且整個表達式返回nil。否則,?之後的東西都會被運行。在這兩種情況下,整個表達式的值也是一個可選值。

1

2

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

let sideLength = optionalSquare?.sideLength

枚舉

使用enum來創建一個枚舉。就像類和其他所有命名類型一樣,枚舉可以包含方法。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

enum Rank: Int {

    case Ace = 1

    case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten

    case Jack, Queen, King

    func simpleDescription() -> String {

        switch self {

        case .Ace:

            return "ace"

        case .Jack:

            return "jack"

        case .Queen:

            return "queen"

        case .King:

            return "king"

        default:

            return String(self.toRaw())

        }

    }

}

let ace = Rank.Ace

let aceRawValue = ace.toRaw()

寫一個函數,通過比較它們的原始值來比較兩個Rank值。

在上面的例子中,枚舉原始值的類型是Int,所以你隻需要設置第一個原始值。剩下的原始值會按照順序賦值。你也可以使用字符串或者浮點數作為枚舉的原始值。

使用toRaw和fromRaw函數來在原始值和枚舉值之間進行轉換。

1

2

3

if let convertedRank = Rank.fromRaw(3) {

    let threeDescription = convertedRank.simpleDescription()

}

枚舉的成員值是實際值,并不是原始值的另一種表達方法。實際上,如果原始值沒有意義,你不需要設置。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

enum Suit {

    case Spades, Hearts, Diamonds, Clubs

    func simpleDescription() -> String {

        switch self {

            case .Spades:

                return "spades"

            case .Hearts:

                return "hearts"

            case .Diamonds:

                return "diamonds"

            case .Clubs:

                return "clubs"

        }

    }

}

let hearts = Suit.Hearts

let heartsDescription = hearts.simpleDescription()

給Suit添加一個color方法,對spades和clubs返回“black”,對hearts和diamonds返回“red”。

注意,有兩種方式可以引用Hearts成員:給hearts常量賦值時,枚舉成員Suit.Hearts需要用全名來引用,因為常量沒有顯式指定類型。在switch裡,枚舉成員使用縮寫.Hearts來引用,因為self的值已經知道是一個suit。已知變量類型的情況下你可以使用縮寫。

使用struct來創建一個結構體。結構體和類有很多相同的地方,比如方法和構造器。它們之間最大的一個區别就是 結構體是傳值,類是傳引用。

1

2

3

4

5

6

7

8

9

struct Card {

    var rank: Rank

    var suit: Suit

    func simpleDescription() -> String {

        return "The (rank.simpleDescription()) of (suit.simpleDescription())"

    }

}

let threeOfSpades = Card(rank: .Three, suit: .Spades)

let threeOfSpadesDescription = threeOfSpades.simpleDescription()

給Card添加一個方法,創建一副完整的撲克牌并把每張牌的 rank 和 suit 對應起來。

一個枚舉成員的實例可以有實例值。相同枚舉成員的實例可以有不同的值。創建實例的時候傳入值即可。

實例值和原始值是不同的:枚舉成員的原始值對于所有實例都是相同的,而且你是在定義枚舉的時候設置原始值。

例如,考慮從服務器獲取日出和日落的時間。服務器會返回正常結果或者錯誤信息。

1

2

3

4

5

6

7

8

9

10

11

12

enum ServerResponse {

    case Result(String, String)

    case Error(String)

}

let success = ServerResponse.Result("6:00 am", "8:09 pm")

let failure = ServerResponse.Error("Out of cheese.")

switch success {

    case let .Result(sunrise, sunset):

        let serverResponse = "Sunrise is at (sunrise) and sunset is at (sunset)."

    case let .Error(error):

        let serverResponse = "Failure... (error)"

}

給ServerResponse和switch添加第三種情況。

注意如何從ServerResponse中提取日升和日落時間。

接口擴展

使用protocol來聲明一個接口。

1

2

3

4

protocol ExampleProtocol {

    var simpleDescription: String { get }

    mutating func adjust()

}

類、枚舉和結構體都可以實現接口。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

class SimpleClass: ExampleProtocol {

    var simpleDescription: String = "A very simple class."

    var anotherProperty: Int = 69105

    func adjust() {

        simpleDescription += " Now 100% adjusted."

    }

}

var a = SimpleClass()

a.adjust()

let aDescription = a.simpleDescription

struct SimpleStructure: ExampleProtocol {

    var simpleDescription: String = "A simple structure"

    mutating func adjust() {

        simpleDescription += " (adjusted)"

    }

}

var b = SimpleStructure()

b.adjust()

let bDescription = b.simpleDescription

寫一個實現這個接口的枚舉。

注意聲明SimpleStructure時候mutating關鍵字用來标記一個會修改結構體的方法。SimpleClass的聲明不需要标記任何方法因為類中的方法經常會修改類。

使用extension來為現有的類型添加功能,比如添加一個計算屬性的方法。你可以使用擴展來給任意類型添加協議,甚至是你從外部庫或者框架中導入的類型。

1

2

3

4

5

6

7

8

9

extension Int: ExampleProtocol {

    var simpleDescription: String {

        return "The number (self)"

    }

    mutating func adjust() {

        self += 42

    }

}

7.simpleDescription

給Double類型寫一個擴展,添加absoluteValue功能。

你可以像使用其他命名類型一樣使用接口名——例如,創建一個有不同類型但是都實現一個接口的對象集合。當你處理類型是接口的值時,接口外定義的方法不可用。

1

2

3

4

let protocolValue: ExampleProtocol = a

    protocolValue.simpleDescription

// protocolValue.anotherProperty 

// Uncomment to see the error

即使protocolValue變量運行時的類型是simpleClass,編譯器會把它的類型當做ExampleProtocol。這表示你不能調用類在它實現的接口之外實現的方法或者屬性。

泛型

在尖括号裡寫一個名字來創建一個泛型函數或者類型。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

func repeat(item: ItemType, times: Int) -> ItemType[] {

    var result = ItemType[]()

    for i in 0..

        result += item

    }

    return result

}

repeat("knock", 4)

// 你也可以創建泛型類、枚舉和結構體。

// Reimplement the Swift standard library's optional type

enum OptionalValue {

    case None

    case Some(T)

}

var possibleInteger: OptionalValue = .None

    possibleInteger = .Some(100)

在類型名後面使用where來指定一個需求列表——例如,要限定實現一個協議的類型,需要限定兩個類型要相同,或者限定一個類必須有一個特定的父類。

1

2

3

4

5

6

7

8

9

10

11

func anyCommonElements  (lhs: T, rhs: U) -> Bool {

    for lhsItem in lhs {

        for rhsItem in rhs {

            if lhsItem == rhsItem {

                return true

            }

        }

    }

    return false

}

anyCommonElements([1, 2, 3], [3])

修改anyCommonElements函數來創建一個函數,返回一個數組,内容是兩個序列的共有元素。

簡單起見,你可以忽略where,隻在冒号後面寫接口或者類名。和是等價的。

上一篇:iQOO

下一篇:弓箭

相關詞條

相關搜索

其它詞條