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语言中的每一个细节都整理出来,希望能和大家一起学习。
一、Swift 语法概述