Swift 語言最小化

swift_tour_learning-swift.jpg

WWDC 2014 上 Apple Duang!!! 一聲發(fā)布了 Swift房轿。在那次發(fā)布會上杜窄, Apple 向外界宣布了望抽,自己其實是一家軟件公司。

2015 年煌妈, Apple 又 Duang!!! 一聲將 Swift 開源儡羔。這讓 Swift 迅速攻占了服務(wù)器,這使 Swift 開發(fā) Backend server 成為了可能( Vapor )璧诵。

初次接觸 Swift汰蜘,讓我看到了 Scala、C#之宿、ES 6 的影子族操,并且語法層面兼容 Objective C。first-class functions 特性讓語言并不局限于 OO比被,讓 Swift 具有函數(shù)式編程語言的表達力色难。 同時,Swift 作者 Chris Lattner 這位傳奇人物的存在等缀,讓 Swift 成為值得長期投資的一門語言枷莉。

本文來自 Swift Tour,將其中的內(nèi)容歸類總結(jié)尺迂,可以當(dāng)做 Cheatsheet 翻閱笤妙,對于具有經(jīng)驗的開發(fā)者,看過這篇便可開始工作了枪狂。

變量

Swift 中可以使用 varlet 直接定義 變量常量危喉。

定義變量:
?

var age = 20// 定義變量
let name = "Halo" // 定義常亮
age = 21

聲明類型:

上段代碼看起來有些類似 javascript 若類型語言的特性,Swift 本質(zhì)上還是強類型的語言州疾,聲明變量的時候辜限,可以指定數(shù)據(jù)類型:

let cash: Float = 1.25
let money: Double = 1.252525
let dollar: String = "USD"

使用 String

對于字符串,Swift 簡化了 Objective C NSString 的定義方式:@""

let currencies = "AUD, " + dollar
let rmb = "1 \(dollar) is 6 RMB"
let formattedString = String(format: "%.2f \(dollar) is about 600 RMB", 100.0) // 100.00 USD is about 600 RMB

\(variable) 是 Swift 為字符串模板提供的支持严蓖。<s>不過 Swift 還是支持類似 ES 6 或者 Ruby 中多行字符串模板薄嫡。多行字符串還是需要 + 號拼接</s> Swift 4.2 開始支持多行字符串:

let introduceSwift = """
  We are excited by this new chapter in the story of Swift.
  After Apple unveiled the Swift programming language, it quickly became one of
  the fastest growing languages in history. Swift makes it easy to write software
  that is incredibly fast and safe by design. Now that Swift is open source, you can
  help make the best general purpose programming language available everywhere.
"""

使用 tuple

tuple 是 Swift 引入的一種新的數(shù)據(jù)類型,它可以方便支持方法的多返回值:

let numbersTuple = (1, 100, 1000)
    print("min: \(numbersTuple.0), max: \(numbersTuple.1), sum: \(numbersTuple.2)")

let numbersNamedTuple = (min: 1, max: 100, sum: 1000)
    print("min: \(numbersNamedTuple.0), max: \(numbersNamedTuple.1), sum: \(numbersNamedTuple.2)")
    print("min: \(numbersNamedTuple.min), max: \(numbersNamedTuple.max), sum: \(numbersNamedTuple.sum)")

Collections

創(chuàng)建集合:

Swift 的集合類型主要還是 ArrayDictionary

var fruits = ["apple", "banana", "oranage"]
var fruitsPrice = [
    "apple": 4.25,
    "banana": 6.2
]
print(fruitsPrice[fruits[1]]) // 6.2

定義空集合:

var emptyArray = [String]()
var emptyDictionary = [String: Float]()

將已有集合設(shè)置為空時颗胡,可以用如下簡寫:

fruits = []
fruitsPrice = [:]

使用 for in 遍歷集合:

for score in [1,2,3,4,5,6] {
    print(score * score * score)
}

for (key, val) in ["one": 1, "two": 2] {
    print("\(val) is \(key)")
}

if else 和 Optional

Swift 中新增一種類型 Optional毫深,這個概念來自 Scala。 Optional 類似一個包裝器毒姨,它可以包裝一個數(shù)值哑蔫,但是 Optional 可能返回 nil,可能返回數(shù)據(jù)。多用于錯誤處理闸迷,通常跟 if else 連用:

聲明 Optional:

var optionalString: String? = nil
//print(optionalString!) // nil 取值會報錯
print(optionalString == nil)

var optionalName: String? = "Jian"
print(optionalName!)

String? 表示一個 String 類型的 Optional嵌纲。只有 Optional 可以接受 nil 值。如果對一個 nil 的 Optional 取值會報錯腥沽,一般取值前會對 Optional 做判斷:

var optionalString: String? = nil

if optionalString != nil {
    let val = optionalString!
} else {
    print("There is no value")
}

if-else 簡化 Optional 取值:

Swift 為上面這種方式提供一種簡寫:

if let val = optionalString {
    print("There is a value: \(val)")
} else {
    print("There is no value")
}

// flatMap
optionalString.flatMap { print("There is a value: \($0)") }

通常會將 if-else 和 Optional 這么使用:

var optionalName: String? = "Jian"
print(optionalName!)

var greeting = "Hello!"

if let name = optionalName {
    greeting = "Hello \(name)"
}

Optional 默認值:

使用 ?? 可以為 Optional 提供默認值:

let fullName: String = "Jian"
let nickName: String? = nil
let displayName = "\(nickName ?? fullName)"

switch

Swift 中的 switch 強大很多逮走,支持 String,多值匹配今阳,條件匹配:

let vegetable = "red pepper"

switch vegetable {
case "celery":
    print("Add some raisins and make ants on a log.")
case "cucumber", "watercress":
    print("Taht would make a good tea sandwich.")
case let x where x.hasSuffix("pepper"):
    print("Is it a spicy \(x)?") // Is it a spicy red pepper?
default:
    print("Everythink tasts good")
}

使用循環(huán)

for in 循環(huán)

Swift 中的 for in 和 javascript 中的有點類似师溅。使用 for in 便利 Dictionary:

let numbersDict = [
    "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 numbersDict {
    for number in numbers {
        number
        if number > largest {
            largest = number
        }
    }
}
print(largest) // 25

使用 for in 遍歷 Range:

var total = 0
for i in 0..<4 {
    total += i
}
print(total) // 6

while 循環(huán)

一般語言都會提供 whiledo {} while 循環(huán)。Swift 采用 whilerepeat {} while

var n = 1
while n < 100 {
    n += n
}
print(n) //128

var m = 1
repeat {
    m += m
} while m < 100
print(m) // 128

Functions

Swift 中的函數(shù)具有 javascript 和 objective c 的雙重特征盾舌。并且函數(shù)在 Swift 中是一等公民(First-class type)墓臭,具有高階函數(shù)的特性。

定義函數(shù)

一般情況下矿筝,跟 Objective C 方法一樣起便,需要給函數(shù)參數(shù)提供 Label:

func greet(person: String, day: String) -> String {
    return "Hello \(person), today is \(day)."
}
greet(person: "Jian", day: "Friday")

使用 _ 表示省略 Label:

func greet(_ person: String, on day: String) -> String {
    return "Hello \(person), today is \(day)."
}
greet("Jian", on: "Friday")

函數(shù)可以使用 tuple 返回多個值:

func calcStatistics(scores: [Int]) -> (min: Int, max: Int, sum: Int) {
    var min = scores[0]
    var max = scores[0]
    var sum = 0
    
    for score in scores {
        if score > max {
            max = score
        } else if score < min {
            min = score
        }
        
        sum += score
    }
    
    return (min, max, sum)
}

let statistics = calcStatistics(scores: [5, 1, 100, 30, 90])
print(statistics.sum) // 226
print(statistics.2)   // 226

無限參數(shù):

func sumOf(numbers: Int...) -> Int {
    return numbers.reduce(0, +)
}
sumOf()                             // 0
sumOf(numbers: 1, 2, 3, 4, 10)      // 20

使用 Int... 在函數(shù)的最后一個參數(shù),表示后面可以接受無限個整數(shù)參數(shù)窖维。

函數(shù)嵌套

func returnFifteen() -> Int {
    var y = 10
    func add() { y += 5 }
    add()
    return y
}
returnFifteen() // 15

高階函數(shù)

高階函數(shù)(high-order function)榆综,是函數(shù)是編程的一個概念,高階函數(shù)的特點:

  • 可以將函數(shù)當(dāng)做返回值铸史,即:可以使用函數(shù)創(chuàng)建函數(shù)
  • 可以將函數(shù)當(dāng)做參數(shù)接收

使用函數(shù)創(chuàng)建另一個函數(shù):

func createIncrementer() -> ((Int) -> Int) {
    func plusOne(number: Int) -> Int {
        return 1 + number
    }
    
    return plusOne
}
let incrementer = createIncrementer()
incrementer(10)

函數(shù)作為參數(shù):

func hasAnyMatches(_ list: [Int], matcher: (Int) -> Bool) -> Bool {
    for item in list {
        if matcher(item) {
            return true
        }
    }
    
    return false
}

func lessThanThen(number: Int) -> Bool {
    return number < 10
}

hasAnyMatches([20, 10, 7, 12], matcher: lessThanThen)

Closure (閉包)

Closure 可以理解匿名函數(shù)鼻疮,在很多 Callback 和集合操作中使用:

hasAnyMatches([20, 10, 7, 12]) { (item: Int) -> Bool in
    item < 10
}
[20, 10, 7, 12].map { (item: Int) -> Int in
    return 3 * item
}
[20, 10, 7, 12].map({ item in 3 * item })

如果省略 () 后, Closure 是唯一的參數(shù):

let sortedNumbers = [20, 10, 7, 12].sorted { $0 > $1 }
print(sortedNumbers)

Objects and Classes

定義和使用類:

class Shape {
    var numberOfSides = 0
    
    func simpleDescription() -> String {
        return "A shap with \(numberOfSides) sides."
    }
}
let shape = Shape()
shape.numberOfSides = 10
shape.simpleDescription()

使用繼承:

class NamedShape : Shape {
    var name: String
    
    init(name: String) {
        self.name = name
    }
}

// inherit and override
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 square = Square(sideLength: 10.0, name: "Jian's Square")
square.area()
square.simpleDescription()

使用屬性

Swift 中對屬性的處理琳轿,有些像 C#判沟。

使用 getter/setter

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 triangle with sides of length \(sideLength)"
    }
}
var triangle = EquilateralTriangle(sideLength: 3.1, name: "A triangle")
print(triangle.perimeter)           // 9.3

triangle.perimeter = 9.9
print(triangle.sideLength)          // 3.3

使用 willSet:

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: "other shape")
print(triangleAndSquare.square.sideLength)          // 10.0
print(triangleAndSquare.triangle.sideLength)        // 10.0

triangleAndSquare.square = Square(sideLength: 50, name: "Large square")
print(triangleAndSquare.triangle.sideLength)        // 50.0

使用 willSet 保證 squaretrianglesideLength 始終相等。

使用 Optional 類型

使用 ?. 取值崭篡,當(dāng)值為 nil 時返回 nil挪哄,而不是報錯。

let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square")
let sideLength = optionalSquare?.sideLength
let nilSquare: Square? = nil
let nilLength = nilSquare?.sideLength

Enumerations

定義 enum 類型:

enum Level: Int {
    case Zero, First, Second
}
Level.Zero.rawValue
Level.First.rawValue

enumrawValue 默認從 0 開始琉闪,依次遞增迹炼。

在 enum 中創(chuàng)建方法:

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"
        }
    }
}

定義特性類型的 enum:

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.rawValue)
        }
    }
}
let ace = Rank.ace                      // ace
let aceRawValue = ace.rawValue          // 1

enum Rank: Int 設(shè)置 enumrawValueInt。我們也可以通過 rawValue 來創(chuàng)建 enum

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

復(fù)雜的 enum

enum ServerResponse {
    case result(String, String)
    case failure(String)
}

let success = ServerResponse.result("6:00 am", "8:00 pm")
let failure = ServerResponse.failure("Out of cheese")

switch success {
case let .result(sunrise, sunset):
    print("Sunrise is at \(sunrise) and sunset is at \(sunset)") // Sunrise is at 6:00 am and sunset is at 8:00 pm
case let .failure(message):
    print("Failure ... \(message)")
}

Structs

struct Card {
    var rank: Rank
    var suit: Suit
    
    func simpleDescript() -> String {
        return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
    }
}
let threeOfSpades = Card(rank: .three, suit: .spades)   // Card
print(threeOfSpades.simpleDescript())                   // The 3 of spades

structclass 最重要的區(qū)別是:

  • struct 傳遞值颠毙,始終傳遞 copy
  • class 傳遞引用斯入。

Protocol

protocol ExampleProtocol {
    var simpleDescription: String { get }
    mutating func adjust()
}

Protocol 與 Java 中的 Interface 概念類似。在 Swift 中蛀蜜,class刻两、struct、enum滴某、extension 都可以實現(xiàn) Protocol:

class 實現(xiàn) protocol:

class SimpleClass: ExampleProtocol {
    var simpleDescription: String = "A simple class."
    var moreProperty: Int = 315
    func adjust() {
        simpleDescription += " Now 100% adjusted"
    }
}
var simpleClass = SimpleClass()
simpleClass.adjust()
print(simpleClass.simpleDescription)        // A simple class. Now 100% adjusted

struct 實現(xiàn) protocol:

struct SimpleStructure: ExampleProtocol {
    var simpleDescription: String = "A simple structure"
    mutating func adjust() {
        simpleDescription += " (adjusted) "
    }
}

var simpleStruct = SimpleStructure()
simpleStruct.adjust()
print(simpleStruct.simpleDescription)

mutating 修飾符表示磅摹,當(dāng)前方法在 struct 中可以修改 struct 的值滋迈。

在 protocol 的應(yīng)用中,可以使用 Java 中面向 Interface 編程:

let protocolValue: ExampleProtocol = simpleStruct
print(protocolValue.simpleDescription)              // A simple structure (adjusted)

Extensions

Swift 中的 extension 和 ruby 中的 Open Class 概念很像偏瓤,在 ObjC 中是 Category杀怠。它可以為已有類型添加新的特性:

extension Int: ExampleProtocol {
    var simpleDescription: String {
        return "The number \(self)"
    }
    
    mutating func adjust() {
        self += 10
    }
}

print(7.simpleDescription)

Error Handling

throws 異常

enum PointerError: Error {
    case outOfPaper
    case noToner
    case onFire
}

// throw error
func send(job: Int, toPointer printerName: String) throws -> String {
    if printerName == "Never has toner" {
        throw PointerError.noToner
    }
    return "Job sent"
}

catch 和處理異常

對于具有 throws 聲明的方法,需要使用 try 關(guān)鍵字調(diào)用厅克,然后使用 do {} catch {} 包裹:

do {
    let pointerResp = try send(job: 1024, toPointer: "Never has toner")
    print(pointerResp)
} catch { // catch all errors
    print(error) // use error by default
}

處理多個異常:

do {
    let pointerResponse = try send(job: 1024, toPointer: "Jian")
    print(pointerResponse)
    throw PointerError.onFire
    
} catch PointerError.onFire {
    print("I'll just put shi over here, with the result of the fire.")      // I'll just put shi over here, with the result of the fire.
} catch let pointerError as PointerError {
    print("Printer error: \(pointerError) .")
} catch {
    print(error)
}

通常 catch 多個 Error 時,catch 順序需要從小異常橙依,到范圍更大的異常证舟。

使用 try?

// try? -> Optional
let pointerFailure = try? send(job: 1024, toPointer: "Never has toner")         // nil
let pointerSuccess = try? send(job: 2048, toPointer: "Good pointer")        // Job sent

使用 defer

在方法 throws 時,會終端當(dāng)前函數(shù)后續(xù)的代碼執(zhí)行窗骑,使用 defer 可以確保 defer 代碼段中的代碼在函數(shù)返回前始終被執(zhí)行女责。這個概念有些像 Java 的 try {} catch {} finally {} 中的 finally

func ensureExecute() throws -> String {
    defer {
        print("Complete")
    }
    
    do {
        try send(job: 1024, toPointer: "Never has toner")
    } catch {
        throw error
    }
    
    return "Executed"
}
let executed = try? ensureExecute()     // Complete

Generic

Swift 開始支持泛型(Generic):

enum OptionalValue<Wrapped> {
    case none
    case some(Wrapped)
}
var possibleInteger: OptionalValue<Int> = .none     // none
possibleInteger = .some(100)                        // some(100)

使用 where 限定泛型的類型:

func anyCommonElements<T: Sequence, U: Sequence>(_ lhs: T, _ rhs: U) -> Bool
    where T.Iterator.Element: Equatable, T.Iterator.Element == U.Iterator.Element {
        
        for lhsItem in lhs {
            for rhsItem in rhs {
                if lhsItem == rhsItem {
                    return true
                }
            }
        }

        return false
}
anyCommonElements([1,2,3,4,5], [5])

where T.Iterator.Element: Equatable, T.Iterator.Element == U.Iterator.Element 限制 TU 中的元素,必須實現(xiàn) Equatable创译,并且 TU 中的元素是同一種類型抵知。

擴展閱讀

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市软族,隨后出現(xiàn)的幾起案子刷喜,更是在濱河造成了極大的恐慌,老刑警劉巖立砸,帶你破解...
    沈念sama閱讀 222,000評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件掖疮,死亡現(xiàn)場離奇詭異,居然都是意外死亡颗祝,警方通過查閱死者的電腦和手機浊闪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來螺戳,“玉大人搁宾,你說我怎么就攤上這事【笥祝” “怎么了盖腿?”我有些...
    開封第一講書人閱讀 168,561評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長凤藏。 經(jīng)常有香客問我奸忽,道長,這世上最難降的妖魔是什么揖庄? 我笑而不...
    開封第一講書人閱讀 59,782評論 1 298
  • 正文 為了忘掉前任栗菜,我火速辦了婚禮,結(jié)果婚禮上蹄梢,老公的妹妹穿的比我還像新娘疙筹。我一直安慰自己富俄,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,798評論 6 397
  • 文/花漫 我一把揭開白布而咆。 她就那樣靜靜地躺著霍比,像睡著了一般。 火紅的嫁衣襯著肌膚如雪暴备。 梳的紋絲不亂的頭發(fā)上悠瞬,一...
    開封第一講書人閱讀 52,394評論 1 310
  • 那天,我揣著相機與錄音涯捻,去河邊找鬼浅妆。 笑死,一個胖子當(dāng)著我的面吹牛障癌,可吹牛的內(nèi)容都是我干的凌外。 我是一名探鬼主播,決...
    沈念sama閱讀 40,952評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼涛浙,長吁一口氣:“原來是場噩夢啊……” “哼康辑!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起轿亮,我...
    開封第一講書人閱讀 39,852評論 0 276
  • 序言:老撾萬榮一對情侶失蹤疮薇,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后哀托,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體惦辛,經(jīng)...
    沈念sama閱讀 46,409評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,483評論 3 341
  • 正文 我和宋清朗相戀三年仓手,在試婚紗的時候發(fā)現(xiàn)自己被綠了胖齐。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,615評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡嗽冒,死狀恐怖呀伙,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情添坊,我是刑警寧澤剿另,帶...
    沈念sama閱讀 36,303評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站贬蛙,受9級特大地震影響雨女,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜阳准,卻給世界環(huán)境...
    茶點故事閱讀 41,979評論 3 334
  • 文/蒙蒙 一氛堕、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧野蝇,春花似錦讼稚、人聲如沸括儒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽帮寻。三九已至,卻和暖如春赠摇,著一層夾襖步出監(jiān)牢的瞬間固逗,已是汗流浹背戴而。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評論 1 272
  • 我被黑心中介騙來泰國打工岸梨, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人院究。 一個月前我還...
    沈念sama閱讀 49,041評論 3 377
  • 正文 我出身青樓耘戚,卻偏偏與公主長得像,于是被迫代替她去往敵國和親操漠。 傳聞我的和親對象是個殘疾皇子收津,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,630評論 2 359

推薦閱讀更多精彩內(nèi)容