【WWDC 2014】帶您一覽蘋果全新編程語言Swift

Apple在WWDC 2014開發者大會上發佈了用於Mac OS X和iOS編程的新一代編程語言Swift。html

在真正可以使用Swift以前,SF先帶你們從Apple的Beta版文檔中,簡單的一覽Swift的基礎用法。ios

請輸入圖片描述

SEGMENTFAULT聲明:本文是根據**未發佈版本**的文檔編譯整理而成的。
咱們沒法保證蘋果公司將來實際發佈的軟件,與本文的狀況徹底一致。編程

注:不要錯過文章末尾的《SF簡評Swift》部分!swift

101:最基本語法

  • 編譯型(LLVM)
  • 等同衆多解釋型語言的實時輸入、實時執行(Playground)
  • 全局域自動執行(無需主函數)
  • 行尾無分號
  • Hello world:println("Hello world")
  • 註釋使用///* */。但塊註釋能夠嵌套
    例如:/* A /* B */ C */就是合法的。
  • =運算符僅用於賦值
    與C不一樣:var = value不是一個合法的表達式
    與C一致的是==運算符仍然是判斷

變量與數據類型

  • 弱類型
  • 變量:var length = 10
  • 常量:let MAX_LENGTH = 100
  • 強制類型:var length: Double = 10 (var or let)
  • 徹底禁止隱式轉換,例如這個是錯誤的:
    println("Length = " + length + " cm")
    必須這樣寫:
    println("Length = " + String(length) + " cm")
    可是在字符串中嵌入數字有一種簡寫法:
    println("Length = \(length) cm")

空值

  • 空值表示爲nil
  • 必須使用?,顯式指定變量能夠賦空值:var optionalString: String? = nil (定義或運行時都可)
  • nil在邏輯判斷中被隱式轉換爲false (這與一般的變量值不得隱式轉換不一樣)

另外,若是待引用的變量值多是nil,通常須要先行判斷。但在Swift中,能夠在下標、方法或對象成員的引用以前加?
這個語法表示若是?前邊的是nil,則後邊的調用所有省略,整個表達式的值是nilsegmentfault

WWDC 2014會上,Craig Federighi 直接展現了這個用法,將數行帶有預判斷的代碼縮成了一行:
包含數個if變量不等於nil的多行語句
<code>myDelegate?.scrollViewDidScroll?(myScrollView)</code>數組

數組與字典

  • 所有使用方括號包裹
  • 數組:[value 1, value 2, value 3]
  • 數組下標從0開始
  • 字典:["key1": value 1, "key2": value 2]
  • 空數組:[],空字典:[:]

流程控制

注意:Swift中任何條件判斷,必須使用真正的布爾值表達式!數值不會按照「0/非0」的習慣規則隱式轉換爲true,而是一概報錯網絡

條件分支

if 判斷

if condition 1 {
    code for condition 1
} else if condition 2 {
    code for condition 2
} else {
    code for none of above
}
  • if語句中,小括號可選,大括號必須

switch 多出口分支

switch variable {
    case value 1:
        code for value 1
    case value 2:
        code for value 1
    default:
        code for none of abolve
}
  • 無需break
  • 能夠一次比較多個值:case value 1, value 2: (值1或值2)
  • 比較條件不限於值,可使用自定義的語句:case let x where x > 10:
  • default分支不得省略。

循環

for-in 遍歷循環

for var_iterator in iterated_array {
    code within loop
}
  • 循環字典:for (key, value) in iterated_dictionary
  • 使用..指定整數的範圍:for index in 1..5

for-condition-increment C風格循環

for var index = 0; index < 3; ++index {
    code within loop
}

while 循環

while condition {
    code
}

do {
    code
} while condition

函數

定義與調用

func greet(name: String, day: String) -> String {
    return "Hello \(name), today is \(day)."
}
greet("Bob", "Tuesday")
  • 一次傳入多個值:定義func f1(p1: Int...) -> Int {code} 調用f1(1, 2, 3)
  • 一次返回多個值:return (3.59, 3.69, 3.79) (藉助tuple)

函數容許嵌套。子函數共享父函數的變量做用域:閉包

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

閉包特性

函數自己是一種數據類型。函數能夠做爲返回值:app

func makeIncrementer() -> (Int -> Int) {
    func addOne(number: Int) -> Int {
        return 1 + number
    }
    return addOne
}
var increment = makeIncrementer()
increment(7)

也能夠把函數自己,做爲參數傳遞給其餘函數:less

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(numbers, lessThanTen)

但必須注意類型必須嚴格等同。

可使用{}定義匿名函數。能夠在花括號內的第一行,使用in關鍵字定義參數和返回值:

numbers.map({
    (number: Int) -> Int in
    let result = 3 * number
    return result
})
  • 但也能夠在類型已知的狀況下省略之。例如:numbers.map({ number in 3 * number })
    這個單行的閉包,只接受一個參數並返回表達式的值。
  • 也可使用數字引用參數。例如:sort([1, 5, 3, 12, 2]) { $0 > $1 }
    這個傳參方式相似Shell。

對象與類

定義與實例化

定義:

class Shape {
    var numberOfSides = 0
    var name: String
    init(name: String) {
        self.name = name
    }
    func simpleDescription() -> String {
        return "A shape with \(numberOfSides) sides."
    }
}

實例化:

var shape = Shape("Triangle")
shape.numberOfSides = 3
println(shape.simpleDescription())
  • 構造:init(name: String) {self.name = name}
  • 析構:deinit() {code}

繼承與多態

  • 繼承在類名後邊加:
  • 使用super關鍵字引用父類
  • 多態必須顯式使用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 test = Square(sideLength: 5.2, name: "my test square")
test.area()
test.simpleDescription()

屬性(property)

可以自定義賦值或取值的代碼的變量被稱爲屬性(property)。

  • 使用get自定義取值,使用set自定義賦值
  • get代碼段中使用return返回取值結果
  • set代碼段中固定使用newValue來表示傳入的值
  • 也可使用willSetdidSet,在賦值先後執行代碼(不影響賦值自己)
class Circle {
    init(radius: Double) {
        self.radius = radius
    }
    var radius: Double {
        didSet {
            perimeter = radius * 6.28
        }
    }
    var perimeter: Double {
        get {
            return 6.28 * radius
        }
        set {
            radius = newValue / 6.28
        }
    }
}
circle = Circle(10)
circle.perimeter // 62.8
circle.perimeter = 31.4
circle.radius // 5

枚舉與結構體

使用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.toRaw())
        }
    }
}
let ace = Rank.Ace
let aceRawValue = ace.toRaw() // 1

使用toRawfromRaw轉換原始值和字面值:

if let convertedRank = Rank.fromRaw(11) {
    let jackDescription = convertedRank.simpleDescription() // "Jack"
}
let jackIndex = Rank.toRaw(Rank.Jack) // 11

上邊的例子中,因爲撲克牌存在數字意義的原始值,因此從Ace開始提供了一個1,然後按順序自動增長。但Swift的枚舉類型,爲了沒有數字意義的枚舉量,也支持不使用原始值的定義方法:enum Color {case Red, Green, Blue}

也能夠在枚舉量上開闢變量空間,用來存儲一些必要的值:

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

結構體

結構體使用struct定義,其定義語法和類很是類似。結構體支持構造器、成員方法等類的特性。

注意:結構體是按值傳遞的,而類/對象是按引用傳遞的。

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()

協議和擴展

使用protocol定義協議:

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

協議能夠用在類、枚舉和結構體上。

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

extension定義擴展,用來爲已有的類型增長新的功能:

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

泛型

使用<>聲明泛型:

func repeat<ItemType>(item: ItemType, times: Int) -> ItemType[] {
    var result = ItemType[]()
    for i in 0..times {
        result += item
    }
    return result
}
repeat("knock", 4)

泛型能夠用在類、枚舉和結構體上。

// Reimplement the Swift standard library's optional type
enum OptionalValue<T> {
    case None
    case Some(T)
}
var possibleInteger: OptionalValue<Int> = .None
possibleInteger = .Some(100)

使用where對泛型提出一些約束:

func anyCommonElements <T, U where T: Sequence, U: Sequence, T.GeneratorType.Element: Equatable, T.GeneratorType.Element == U.GeneratorType.Element> (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])

SF簡評Swift

Swift無疑是本次WWDC 2014中,貼近蘋果開發者的最大亮點。

Swift並非對語言思想的本質革新,而是從當前的各類優秀語言中博採衆家之長,從而製成爲蘋果平臺提供的優秀工具。

Swift尤爲是對於各類「坑」的處理很是用心。例如:

  • 嵌套註釋
  • 封鎖隱式類型轉換
  • 封鎖隱式邏輯判斷
  • ……

這些對於新手和老手而言,都是好的。「減輕新手痛苦,節約老手時間」——我想起了這一句廣告詞。

咱們相信Swift(至少在部分場合下)做爲Objective-C的代用語言,將在蘋果開發過程當中發揮不可或缺的做用。

咱們目前主要對Swift存疑的地方有:

  1. 浮誇的Benchmark數據。
    WWDC大會上Swift宣傳相對Python等語言數十至數百倍的性能提高,是一種純粹的廣告口徑——由於優秀編程語言之間出現如此巨大的性能差距,這自己就不太現實。咱們期待未來能有第三方,對Swift自己給出資料和樣例數據充分的公正的Benchmark。
  2. Swift的開源程度。
    編程語言做爲系統基礎工具,其行爲的透明性是很是關鍵的。斯諾登把世界嚇怕了——但願本身的代碼可以放心使用,而不至於在編程語言這一層面,就存在被植入預期之外的行爲,這是如今的某些開發者客觀存在的一個合理擔心。
  3. Swift的應用領域。
    Swift究竟會成爲一門通用的編程語言,仍是隻是做爲蘋果SDK的一部分而存在?這一點和Swift的開源程度是有重疊的——開源也許就意味着廣爲使用,而閉源就等同於Swift專用於蘋果平臺。

咱們不肯意作任何的預先判斷,只期待Swift公佈後實際的表現如何。

Swift相關閱讀推薦

語言介紹

蘋果官方文檔:(Pre-relase,發佈前版本)
A Swift Tour, The Swift Programming Language, iOS Developer Library — Pre-Release
本文不少內容來自於對該文檔的翻譯。
來自其餘做者的同一譯文:來自蘋果的編程語言——Swift簡介

網絡討論

如何評價 Swift 語言?
新發布的 Swift 語言對初學者來講是新的機遇嗎?


SegmentFault編譯原創文章,轉載請遵照本站相關聲明。 外文原做者:Apple Inc. 編譯與原創部分:沙渺 責任編輯:沙渺

相關文章
相關標籤/搜索