2014年的WWDC(苹果全球开发者大会)大会[1]上,当Craig Federighi[2]向全世界宣布“We have new programming language”(我们有了新的编程语言)的时候,全场响起了最热烈和持久的掌声,伴随着掌声到来的语言叫Swift。接下来Craig Federighi更是毫不掩饰的告诉大家,Swift将成为主宰iOS和Mac开发的统治性语言(这句话的潜台词就是Swift将取代Objective-C,Objective-C的时代已经过去了),甚至是整个软件行业中最举足轻重的语言。
Swift正如它的名字那样迅速、敏捷,但这并不是它的全部。Swift是一个博采众长的语言,Chris Lattner博士在设计Swift的时候汲取了Objective-C、Rust、Haskell、Ruby、C#和JavaScript等众多优秀编程语言的优点,并且将面向对象编程和函数式编程的优势完美的融合在一起,最终形成了Swift的核心语法。正因如此,每个程序员都能从Swift中找到自己熟悉的编程语言的影子。在WWDC大会后不到一个月的时间里,Swift已经在编程语言排行榜[4]上进入前20名,虽然不知道是不是后无来者,但这已经是前无古人之举了。
一、变量、常量和字符串
var greeting:String = "Hello, world!" println(greeting)
在上面的代码中greeting是一个变量,它的类型是String(字符串),既然是变量,也就意味着它的值是可以修改的,如下所示:
var greeting:String = "Hello, world!" println(greeting) greeting = "Goodbye world!" println(greeting)
当然,在声明变量时也可以像下面这样写:
var greeting = "Hello, world!"
如果你这样做了,编译器会根据你赋给变量的值进行类型推断(type inference)并确定变量的类型,上面的代码中变量greeting的类型被推断为字符串,相信这个不难理解。当然,由于类型推断的存在,Swift是静态类型的语言,也就是说编译器在编译过程中会检查出类型错误,并提示开发者尽早修正程序中存在的问题。如下所示:
ver greeting = "Hello, world!" greeting = 123 println(greeting)
对于上面的代码,编译器会在第2行报出“type 'String' does not conform to protocol 'IntegerLiteralConvertible'”的错误
【专家建议】可以省略类型标记尽可能使用类型推断来让你的代码更简短并获得更好的可读性。
let num= 123 num = 321
在上面的代码中,我们将声明变量的关键字var换成了let,这样num不再是变量而是常量,也就是说它的值不能在首次赋值后被再次修改。
【专家建议】只要可以应当声明常量而不是变量,这样做不仅会让你的代码更健壮,而且编译器也可以对代码进行进一步的优化获得更好的性能。
Swift允许在一行代码中声明多个变量时将类型标记放在最后面,代码如下所示:
var x, y, z: Double;
还有一点需要说明,对于常量和变量的命名,Swift几乎可以使用任意的Unicode字符,除了空格、数学符号、箭头、特殊用途或无效的Unicode字符,当然数字可以放在除了变量或常量首字母的任何地方。请看下面的例子:
说明:特殊符号可以用搜狗拼音或者Xcode中的特殊字符来输入,可以在Xcode的Edit菜单中找到Special Characters菜单项来选择输入特殊字符,如下图所示。
二、分号
很多语言都是以分号作为语句的分隔符,还有一部分语言要求一行只能书写一条语句(相当于用换行符作为语句的分隔符)。在这一点上,Swift做了一个折衷,如果一行只书写一条语句则可以不使用分号来表示语句的结束;如果一行有多于一条语句,则语句间需要用分号隔开。
var x = 10; println(x)
【专家建议】在Swfit编程中尽量做到一行一条语句而不去使用分号,分号会占用一个字符的空间但对你的程序没有任何的帮助。
三、数值类型和类型转换
var radius = 4 let PI = 3.1416
上面的代码创建了一个数值型的变量和一个数值型的常量,它们的类型分别是Int和Double。Swift中表示整数的类型很多,例如:Int8(8位有符号整数)、UInt16(16位无符号整数),此外表示小数类型的还有Float。需要指出的是,除非你的程序有特殊的需求,Int和Double应当是表示整数和小数的首选,绝大多数应用程序都可以使用Int和Double来搞定所有的数值,而且编译会根据你的系统是32位还是64位的来决定Int类型的大小。
在Swift中,可以在书写数值型的字面量时使用下划线来增强数值的可读性,如下所示:
var million = 1_000_000
当然,在给变量赋值时允许使用运算符计算出数值,但是需要参与运算的各个部分类型保持一致,如下所示:
var radius = 4 let PI = 3.1416 var area = radius * radius * PI
上面的代码会报出编译错误“cannot invoke '*' with an argument list of type '($T4, Double)”。在Swift中,所有的运算符本质都是函数,上面的错误是告诉我们乘法函数无法接受一个Int型作为左值又接受一个Double型作为其右值,正确的改法如下所示:
var area = Double(radius) * Double(radius) * PI
你也许会认为上面的操作就是所谓的类型转换,其实不然,代码Double(radius)创建了新的Double型的对象然后用radius的值进行了初始化操作。如果不清楚什么意思,没关系,接着往下看。
【专家建议】可以按住键盘上的Command键再点击Swift中的类型来查看头文件中对类型、函数、协议等的定义。
当变量的值超出了变量的表示范围时,Swift会报出编译错误来阻止这样的操作,这是Swift在编程安全方面做的处理。
四、布尔型
Swift中有布尔类型,布尔类型只有两种取值true或者false。下面的代码演示了如果创建布尔类型的常量:
let alwaysTrue = true
布尔类型经常被用于循环和分支结构,在Swift中,循环和分支结构中的条件只能使用布尔类型的值,这一点不同于C、C++和Objective-C。
五、元组
元组是由多个值组成的单一类型,与类和结构体不同,你不需要定义元组类型就能使用它。
var address = (610000, "Chengdu Sichuan") println(address.0) println(address.1) address.0 = 618000 address.1 = "Deyang Sichuan" let (zipcode, city) = address println(zipcode) println(city)
上面的代码使用了类型推断来得到元组的数据类型,当然你也可以书写如下的代码来指定元组中的数据对应的数据类型:
var address: (Int, String) = (610000, "ChengduSichuan")
此外,还可以为元组中的数据命名,如下所示:
var address = (zipcode: 610000, city: "ChengduSichuan") println(address.zipcode) println(address.city)
【专家建议】元组只适用于快速的构造简单的复合数据类型,更多的时候我们需要的还是类和结构体。
六、字符串插值
如果你用过其他语言拼接字符串的操作,你才能体会到Swift中的字符串插值有多么的方便,要不我们用Java代码写一个两个数求和并输出结果的程序:
package com.lovo; public class TestAdd { public static void main(String[] args) { int a = 123, b = 321; System.out.println(a + " + " + b + " = " + (a + b)); } }
当然,在Java 5以后你可以使用字符串格式化的功能来格式化你的输出,这比拼接字符串感觉上好了很多,如下所示:
package com.lovo; public class TestAdd { public static void main(String[] args) { int a = 123, b = 321; System.out.printf("%d + %d = %d\n", a, b, a + b); } }
但是,在Swift中你可以用字符串插值来优雅的完成上面的操作,代码如下所示:
var a = 123 var b = 321 println("\(a) + \(b) = \(a+b)")
七、流程控制
如果你有其他任何编程语言的经验,对于流程控制的概念一定不会陌生。不管你使用什么样的语言,不管你的程序是简单还是复杂,程序中的代码只有三种结构:顺序结构、分支结构和循环结构。顺序结构相信不难理解,就是按照步骤一步一步的执行,从第一步到最后一步;分支结构是程序中需要做决策的地方,决策的结果不同,程序就会沿着不同的分支执行,例如写程序控制机器人从流水线上将生产的球取出来,如果是红色就放到A框中,如果是蓝色就放到B框中,判断球的颜色就是做决策的地方,而将球放入A框或B框就是两个不同的分支;循环结构是程序中的某些步骤需要重复的执行,例如流水线上会源源不断的将球送到机器人的手上,那么机器人就要重复刚才的根据球的颜色将球放入A框或B框的动作。
下面用一个最简单的1-100求和的程序来演示Swift中的循环。
1. for循环
var sum1: Int = 0 for var i = 1; i <= 100; i++ { sum1 += i } println(sum1)
可以在for循环中使用范围运算符,代码如下所示:
var sum2: Int = 0 for i in 1...100 { sum2 += i } println(sum2)
再看一个例子吧:
2. while循环
var sum3: Int = 0 var i = 1 while i <= 100 { sum3 += i++ } println(sum3)
3. do-while循环
var sum4: Int = 0 var j = 1 do { sum4 += j++ } while j <= 100 println(sum4)
再看看Swift中的分支结构吧。
1. if-else
var greeting: String = "We Will Rock You" var range = 0...11 for i in range { if i % 3 == 0 { println(greeting.uppercaseString) } else if i % 3 == 1 { println(greeting) } else { println(greeting.lowercaseString) } }
2. switch-case-default
var dir = "up" switch dir { case "down": println("Going down!") case "up": println("Going up!") default: println("Going nowhere!") }
对于有其他语言编程经验的人来说上面的代码没有什么难度,事实上,从Swift身上,程序员总能找到自己熟悉的语言的影子,因此对于非零基础的初学者来说,Swift上手还是比较容易的。但是Swift中的循环和分支结构还是有自己的特点,首先省略了对设置条件的圆括号的使用(这一点和C、C++、Java、Objective-C都是不一样的),另外条件只能是布尔类型的值(这一点和C、C++、Object-ive-C是不同的,与Java一致),此外,switch-case-default每个case后面不需要写break,只有一个case或default会执行,default是必须得写的;如果真的希望执行完一个case后继续执行后续的case,可以在case之后写上fallthrough;还有每个case可以写多个常量或范围与switch中的表达式进行等值匹配,而且switch接受的表达式还可以是Swift中的元组类型。且看下面的代码。
let salary = 7000 switch salary { case 0: println("无业游民") case 1...3000: println("码畜") case 3001...6500: println("码农") case 6501...10000: println("IT民工") case 10001...20000: println("IT工程师") case 20001...50000: println("IT人才") default: println("IT精英") }
[1] WWDC2014的视频可以在腾讯视频或优酷上观看,这里分享一个优酷的链接http://v.youku.com/v_show/id_XNzIxODIwNjgw.html
[2] 为什么是Craig Federighi而不是由Tim Cook本人来宣布这么重要的事情,可以看看这个帖子
http://www.36kr.com/p/203972.html
[3] 关于Chris Lattner博士的事迹、他对苹果公司以及软件行业的贡献可以从维基百科上得到相关的信息http://en.wikipedia.org/wiki/Chris_Lattner
[4] Tiobe Index,http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html
[5] 学习Swift最好的教程当然是官方文档The Swift Programming Language,可以在iBook中获得此书或者从官方网站下载pdf文档