首页 > 代码库 > 一、Swift 语法概述

一、Swift 语法概述

  Swift是Apple最新推出的语言,用于编写iOS和OS X程序,与C语言和Objective-C兼容。本系列的文章中的一些例子,都来自于苹果官方的GUIDE: The Swift Programming Language,有兴趣的同学可以去苹果的官网下载英文原版的iBook。

一、Hello world

  Swift中不需要main函数,也不需要用;分开每一行的语句,一个简单的Hello world如下所示:

println("Hello, world")

二、赋值

  使用let来创建一个常量,使用var来创建一个变量,如下所示:

var myVariable = 42
myVariable = 50
let myConstant = 42

  如果初始值没有提供足够多的类型信息,需要用冒号来定义变量类型:

let implicitInt = 72
let implicitDouble = 72.0
let explicitDouble : Double = 72

  如上所示,变量可以隐式定义类型,也可以用冒号来显式定义类型。

  但是,变量在初始化之外,永远都不会隐式转换类型的。例如有变量:

let label = "number is "
let num = 5

  那么,下面的语句是错的:

let numLabel = label + num

  原因是字符串不能与整型相加,那么正确的写法应该是:

let numLabel = label + String(num)

  有一种更简单的方法来包含需要转换的值,就是在双引号中使用反斜杠\来获取变量的字符串型值:

let numLabel = "number is \(num)"

  可以用方括号[ ]来创建词典和数组:

var shoppingList = ["catfish", "water"]
shoppingList[1] = "bottle of water"
var occupations = [
    "Malcolm":  "Captain",
    "Kaylee": "Mechanic",
]
occupations["Jayne"] = "Public Relations"

  用初始化器创建一个空白的词典或列表:

let emptyArray = [String]()
let emptyDictionary = Dictionary<String, Float>()

  当数组或类型的值可以被推断出来时,可以用[ ] 代表一个空白数组,用[:]代表一个空白词典。

三、流程控制


1、if、switch case条件控制

  if、switch中的条件不需要括号,且switch语句中的case不需要加break,因为case中的语句不会跳转到下一个case中。例如:

let hello = "hello"
switch hello {
case "hello":
    let lang = "English"
case "你好":
    let lang = "Chinese"
default:
    let lang = "other"
}

let score = 62
if score >= 60 {
    let result = "Passed"
} else {
    let result = "No pass"
}

  if语句中的条件一定要为布尔值,而不是像C语言那样传入0和非0即可。


2、for、for-in、while、do while循环控制

  循环语句中的条件同样无需添加括号。当在for-in语句中使用一对值时,可以对辞典的键、值进行迭代,例如下面是一个返回辞典中最大值的代码:

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

  可以在for语句中用..<来简化代码的编写,以下是两段等效的代码:

for i in 0..<4{ }
for var i=0; i < 4; ++i { }

四、函数和闭包

  使用func定义一个函数,用 -> 表示函数的返回类型,类似于C++11中的函数返回类型后置。函数形参与类型直接用冒号隔开,形参与形参之间用逗号隔开。

func greet(name: String, day: String) -> String {
    return "Hello \(name), today is \(day)."
}
greet ("Froser", "Sunday")

  可以使用元组(Tuple)来使函数返回多个值:
func getNumber() -> (Double, Double) {
    return (1.0, 2.0)
}

  可以使用...来接收不定长参数,这些不定长参数将作为一个列表:

func sumOf(numbers: Int...) -> Int {
    var sum = 0;
    for number in numbers {
        sum += number
    }
}
sumOf()
sumOf(1,3,100)

  函数可以被嵌套,被嵌套的函数可以访问外部函数的变量:

func test() -> Int {
    var x = 10
    func add(){
        x += 5
    }
    add()
    return x
}

  函数也是一种类型,例如,我们可以让一个函数返回另外一个函数并调用它。

func makeIncrement() -> (Int -> Int) {
    func increase(number: Int) -> Int {
        return number + 1
    }
    return increase
}

  如上所示,makeIncrement返回一个接受一个参数为Int,返回值为Int的函数。在C++中,如果要返回函数,一般是返回函数的地址,在C#中,我们可以把内部的嵌套函数作为一个Lambda表达式来返回,也可以返回一个函数的委托。

  同理,函数的形参也可以为函数:

func equals (numberA: Int, numberB: Int, equals: (Int, Int) -> Bool ) -> Bool {
    return equals(numberA, numberB)
}

  Swift支持匿名函数,你可以把匿名函数看成一个变量,只不过它可以被调用而已。匿名函数不能包含函数名,且要用in来分开函数签名和函数体:

object.save({
    (number: Int) -> Int in
    let result = 3 * number
    return result
    })

五、类与对象

  使用class关键字来创建一个类,类内部可以添加变量、常量和方法(Method)

 

class Shape{
    var numberOfSides = 0
    func description() -> String {
        return "A shape with \(numbeOfSides) sides."
    }
}

  如同一般的面向对象编程,用“.”访问对象中的成员。

var shape = Shape()
shape.numberOfSides = 7

  使用init方法来为类创建一个构造器,用deinit为类创建一个析构器。

  就像C++、C#那样,通过在类名称后面加冒号可以表示类的继承。如果子类要覆盖一个基类方法,必须要加上关键字override。意外地覆盖了基类方法却没有加override会导致编译器报错。

class A{
    func test(){}
}
class B : A{
    override func test(){}
}

  可以像C#那样,在类中定义属性,并编写它们的get和set方法:

class A{
    var _property : String = ""
    var property : String{
        get{
            return "hello " + _property
        }
        set{
            _property = newValue
        }
    }
}

  在为property赋值时,会调用set方法,取值时会调用get方法。set方法中的newValue表示property被赋予的值。

  除此之外,Swift还定义了两种属性方法:willSet和didSet,分别代表属性赋值前和赋值后执行的方法。

  Swift中,类中的func被称为“方法(Method)”,方法可以访问类成员中的值:

class Counter {
    var count: Int = 0
    func add() {
        count++
    }
}

六、枚举

  使用enum关键字创建一个枚举类型,并用case定义它的枚举值。枚举类型可以看成是一个类,因为它可以包含自己的方法,当调用自身方法时,一个使用self获取自身的信息:

enum Rank: Int {
    case Ace = 1
    case Two, Three, Four
    func description() -> String {
        switch self {
            case .Ace:
                return "ace"
            default:
                return String(self.toRaw())
        }
    }
}

  如上所示,我们定义了枚举类型Rank,并为它定义了其原始类型为Int。如果原始类型不重要,你也可以不提供,即去掉“: Int”,此时你亦不可为枚举成员赋予初值。

  当编译器能够推断出枚举对象的类型时,不必在赋值时加上枚举类型名,如可以将Rank.Ace简化为.Ace。

  枚举成员甚至可以带参数:

enum ServerResponse{
    case Success(String)
    case Error(String)
}

let error = ServerResponse.Error("Password incorrect!")

七、结构

  使用关键字struct创建一个结构,与“类”不同的是,结构在传递时,是按照值传递的,而拷贝则是按照“引用”来传递的。请参考C#、Java中的值传递、引用传递。

八、协议

  协议如同C#、Java中的“接口(Interface)”:

protocol Example{
    var description: String { get }
    mutating func adjust()
}

  继承了此协议的类、结构,都必须实现description属性的get方法,以及adjust方法。

  在结构中,实现adjust方法必须在前面添加关键字mutating,表示它会改变自身内部成员的值,而class本身就可以改变自身成员的值,就不必添加了:

class ClassWithDescription : Example {
    var description: String= "very simple"
    func adjust(){
        description=""
    }
}

struct StructWithDescription : Example {
    var description: String= "very simple"
    mutating func adjust(){
        description=""
    }
}

  如同面向对象设计那样,可以用Example类型来定义任何继承了Example协议的对象,但是它只会包含Example协议中的细节。

九、扩展

  如同C#中的扩展方法、Objective-C中的类别,使用extension关键字到一个已知类型,我们可以为这种类型添加扩展的属性、方法。

extension Int: Example{
    ....
}

extension Int{
    ....
}

十、泛型

  Swift中有泛型函数、泛型方法、泛型结构、泛型枚举、泛型结构等。泛型的类型写在尖括号<>中:

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

  可以在尖括号中加入where来约束泛型:

func test<T where T: Sequence> (arg: T){
    ....
}

十一、总结

  以上是列举了一些Swift的语法点,可见Swift吸取了很多语言的成功经验:如Javascript的动态与随意性、C#的属性机制、泛型机制、Java的枚举机制、C++11的后置类型返回,以及简化了for循环的一些写法(这个可能是和Perl学的),让它能成为一门真正的面向对象动态型语言。

  之后,我会将Swift语言中的每一个细节都整理出来,希望能和大家一起学习。