swift是什么?
swift是苹果于wwdc 2014发布的编程语言,这里引用the swift programming language的原话:
swift is a new programming language for ios and os x apps that builds on the best of c and objective-c without the constraints of c compatibility.
swift adopts safe programming patterns and adds modern features to make programming easier more flexible and more fun.
swift’s clean slate backed by the mature and much-loved cocoa and cocoa touch frameworks is an opportunity to imagine how software development works.
swift is the first industrial-quality systems programming language that is as expressive and enjoyable as a scripting language.
简单的说:
swift用来写ios和os x程序。(估计也不会支持其它屌丝系统)
swift吸取了c和objective-c的优点,且更加强大易用。
swift可以使用现有的cocoa和cocoa touch框架。
swift兼具编译语言的高性能(performance)和脚本语言的交互性(interactive)。
swift语言概览
基本概念
注:这一节的代码源自the swift programming language中的a swift tour。
hello world
类似于脚本语言,下面的代码即是一个完整的swift程序。
1
println(" hello world" )
变量与常量
swift使用var声明变量,let声明常量。
1
2
3
var myvariable = 42
myvariable = 50
let myconstant = 42
类型推导
swift支持类型推导(type inference),所以上面的代码不需指定类型,如果需要指定类型:
1
let explicitdouble : double = 70
swift不支持隐式类型转换(implicitly casting),所以下面的代码需要显式类型转换(explicitly casting):
1
2
3
let label = " the width is "
let width = 94
let width = label + string(width)
字符串格式化
swift使用\(item)的形式进行字符串格式化:
1
2
3
4
let apples = 3
let oranges = 5
let applesummary = " i have \(apples) apples."
let applesummary = " i have \(apples + oranges) pieces of fruit."
数组和字典
swift使用[]操作符声明数组(array)和字典(dictionary):
1
2
3
4
5
6
7
8
var shoppinglist = [" catfish" " water" " tulips" " blue paint" ]
shoppinglist[1] = " bottle of water"
var occupations = [
" malcolm" : " captain"
" kaylee" : " mechanic"
]
occupations[" jayne" ] = " public relations"
一般使用初始化器(initializer)语法创建空数组和空字典:
1
2
let emptyarray = string[]()
let emptydictionary = dictionary< string float> ()
如果类型信息已知,则可以使用[]声明空数组,使用[:]声明空字典。
控制流
概览
swift的条件语句包含if和switch,循环语句包含for-in、for、while和do-while,循环/判断条件不需要括号,但循环/判断体(body)必需括号:
1
2
3
4
5
6
7
8
9
let individualscores = [75 43 103 87 12]
var teamscore = 0
for score in individualscores {
if score > 50 {
teamscore += 3
} else {
teamscore += 1
}
}
可空类型
结合if和let,可以方便的处理可空变量(nullable variable)。对于空值,需要在类型声明后添加?显式标明该类型可空。
1
2
3
4
5
6
7
8
var optionalstring: string? = " hello"
optionalstring == nil
var optionalname: string? = " john appleseed"
var gretting = " hello!"
if let name = optionalname {
gretting = " hello \(name)"
}
灵活的switch
swift中的switch支持各种各样的比较操作:
1
2
3
4
5
6
7
8
9
10
11
let vegetable = " red pepper"
switch vegetable {
case " celery" :
let vegetablecomment = " add some raisins and make ants on a log."
case " cucumber" " watercress" :
let vegetablecomment = " that would make a good tea sandwich."
case let x where x.hassuffix(" pepper" ):
let vegetablecomment = " is it a spicy \(x)?"
default:
let vegetablecomment = " everything tastes good in soup."
}
其它循环
for-in除了遍历数组也可以用来遍历字典:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
while循环和do-while循环:
1
2
3
4
5
6
7
8
9
10
11
var n = 2
while n < 100 {
n = n 2
}
n
var m = 2
do {
m = m 2
} while m < 100
m
swift支持传统的for循环,此外也可以通过结合..(生成一个区间)和for-in实现同样的逻辑。
1
2
3
4
5
6
7
8
9
10
11
var firstforloop = 0
for i in 0..3 {
firstforloop += i
}
firstforloop
var secondforloop = 0
for var i = 0 i < 3 ++i {
secondforloop += 1
}
secondforloop
注意:swift除了..还有...:..生成前闭后开的区间,而...生成前闭后闭的区间。
函数和闭包
函数
swift使用func关键字声明函数:
1
2
3
4
func greet(name: string day: string) -> string {
return " hello \(name) today is \(day)."
}
greet(" bob" " tuesday" )
通过元组(tuple)返回多个值:
1
2
3
4
func getgasprices() -> (double double double) {
return (3.59 3.69 3.79)
}
getgasprices()
支持带有变长参数的函数:
1
2
3
4
5
6
7
8
9
func sumof(numbers: int...) -> int {
var sum = 0
for number in numbers {
sum += number
}
return sum
}
sumof()
sumof(42 597 12)
函数也可以嵌套函数:
1
2
3
4
5
6
7
8
9
func returnfifteen() -> int {
var y = 10
func add() {
y += 5
}
add()
return y
}
returnfifteen()
作为头等对象,函数既可以作为返回值,也可以作为参数传递:
1
2
3
4
5
6
7
8
func makeincrementer() -> (int -> int) {
func addone(number: int) -> int {
return 1 + number
}
return addone
}
var increment = makeincrementer()
increment(7)
1
2
3
4
5
6
7
8
9
10
11
12
13
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)
闭包
本质来说,函数是特殊的闭包,swift中可以利用{}声明匿名闭包:
1
2
3
4
5
numbers.map({
(number: int) -> int in
let result = 3 number
return result
})
当闭包的类型已知时,可以使用下面的简化写法:
1
numbers.map({ number in 3 number })
此外还可以通过参数的位置来使用参数,当函数最后一个参数是闭包时,可以使用下面的语法:
1
sort([1 5 3 12 2]) { $0 > $1 }
类和对象
创建和使用类
swift使用class创建一个类,类可以包含字段和方法:
1
2
3
4
5
6
class shape {
var numberofsides = 0
func simpledescription() -> string {
return " a shape with \(numberofsides) sides."
}
}
创建shape类的实例,并调用其字段和方法。
1
2
3
var shape = shape()
shape.numberofsides = 7
var shapedescription = shape.simpledescription()
通过init构建对象,既可以使用self显式引用成员字段(name),也可以隐式引用(numberofsides)。
1
2
3
4
5
6
7
8
9
10
11
12
class namedshape {
var numberofsides: int = 0
var name: string
init(name: string) {
self.name = name
}
func simpledescription() -> string {
return " a shape with \(numberofsides) sides."
}
}
使用deinit进行清理工作。
继承和多态
swift支持继承和多态(override父类方法):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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()
注意:如果这里的simpledescription方法没有被标识为override,则会引发编译错误。
属性
为了简化代码,swift引入了属性(property),见下面的perimeter字段:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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 triagle with sides of length \(sidelength)."
}
}
var triangle = equilateraltriangle(sidelength: 3.1 name: " a triangle" )
triangle.perimeter
triangle.perimeter = 9.9
triangle.sidelength
注意:赋值器(setter)中,接收的值被自动命名为newvalue。
willset和didset
equilateraltriangle的构造器进行了如下操作:
为子类型的属性赋值。
调用父类型的构造器。
修改父类型的属性。
如果不需要计算属性的值,但需要在赋值前后进行一些操作的话,使用willset和didset:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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: " another test shape" )
triangleandsquare.square.sidelength
triangleandsquare.square = square(sidelength: 50 name: " larger square" )
triangleandsquare.triangle.sidelength
从而保证triangle和square拥有相等的sidelength。
调用方法
swift中,函数的参数名称只能在函数内部使用,但方法的参数名称除了在内部使用外还可以在外部使用(第一个参数除外),例如:
1
2
3
4
5
6
7
8
class counter {
var count: int = 0
func incrementby(amount: int numberoftimes times: int) {
count += amount times
}
}
var counter = counter()
counter.incrementby(2 numberoftimes: 7)
注意swift支持为方法参数取别名:在上面的代码里,numberoftimes面向外部,times面向内部。
?的另一种用途
使用可空值时,?可以出现在方法、属性或下标前面。如果?前的值为nil,那么?后面的表达式会被忽略,而原表达式直接返回nil,例如:
1
2
3
let optionalsquare: square? = square(sidelength: 2.5 name: " optional
square" )
let sidelength = optionalsquare?.sidelength
当optionalsquare为nil时,sidelength属性调用会被忽略。
枚举和结构
枚举
使用enum创建枚举——注意swift的枚举可以关联方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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()
使用toraw和fromraw在原始(raw)数值和枚举值之间进行转换:
1
2
3
if let convertedrank = rank.fromraw(3) {
let threedescription = convertedrank.simpledescription()
}
注意枚举中的成员值(member value)是实际的值(actual value),和原始值(raw value)没有必然关联。
一些情况下枚举不存在有意义的原始值,这时可以直接忽略原始值:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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"
}
}
}
let hearts = suit.hearts
let heartsdescription = hearts.simpledescription()
除了可以关联方法,枚举还支持在其成员上关联值,同一枚举的不同成员可以有不同的关联的值:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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)"
}
结构
swift使用struct关键字创建结构。结构支持构造器和方法这些类的特性。结构和类的最大区别在于:结构的实例按值传递(passed by value),而类的实例按引用传递(passed by reference)。
1
2
3
4
5
6
7
8
9
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)和扩展(extension)
协议
swift使用protocol定义协议:
1
2
3
4
protocol exampleprotocol {
var simpledescription: string { get }
mutating func adjust()
}
类型、枚举和结构都可以实现(adopt)协议:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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
扩展
扩展用于在已有的类型上增加新的功能(比如新的方法或属性),swift使用extension声明扩展:
1
2
3
4
5
6
7
8
9
extension int: exampleprotocol {
var simpledescription: string {
return " the number \(self)"
}
mutating func adjust() {
self += 42
}
}
7.simpledescription
泛型(generics)
swift使用< > 来声明泛型函数或泛型类型:
1
2
3
4
5
6
7
8
func repeat< itemtype> (item: itemtype times: int) -> itemtype[] {
var result = itemtype[]()
for i in 0..times {
result += item
}
return result
}
repeat(" knock" 4)
swift也支持在类、枚举和结构中使用泛型:
1
2
3
4
5
6
7
// reimplement the swift standard library s optional type
enum optionalvalue< t> {
case none
case some(t)
}
var possibleinteger: optionalvalue< int> = .none
possibleinteger = .some(100)
有时需要对泛型做一些需求(requirements),比如需求某个泛型类型实现某个接口或继承自某个特定类型、两个泛型类型属于同一个类型等等,swift通过where描述这些需求:
1
2
3
4
5
6
7
8
9
10
11
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])
swift语言概览就到这里,有兴趣的朋友请进一步阅读the swift programming language。
接下来聊聊个人对swift的一些感受。
个人感受
注意:下面的感受纯属个人意见,仅供参考。
大杂烩
尽管我接触swift不足两小时,但很容易看出swift吸收了大量其它编程语言中的元素,这些元素包括但不限于:
属性(property)、可空值(nullable type)语法和泛型(generic type)语法源自c#。
格式风格与go相仿(没有句末的分号,判断条件不需要括号)。
python风格的当前实例引用语法(使用self)和列表字典声明语法。
haskell风格的区间声明语法(比如1..3,1...3)。
协议和扩展源自objective-c(自家产品随便用)。
枚举类型很像java(可以拥有成员或方法)。
class和struct的概念和c#极其相似。
注意这里不是说swift是抄袭——实际上编程语言能玩的花样基本就这些,况且swift选的都是在我看来相当不错的特性。
而且,这个大杂烩有一个好处——就是任何其它编程语言的开发者都不会觉得swift很陌生——这一点很重要。
拒绝隐式(refuse implicity)
swift去除了一些隐式操作,比如隐式类型转换和隐式方法重载这两个坑,干的漂亮。
swift的应用方向
我认为swift主要有下面这两个应用方向:
教育
我指的是编程教育。现有编程语言最大的问题就是交互性奇差,从而导致学习曲线陡峭。相信swift及其交互性极强的编程环境能够打破这个局面,让更多的人——尤其是青少年,学会编程。
这里有必要再次提到brec victor的inventing on principle,看了这个视频你就会明白一个交互性强的编程环境能够带来什么。
应用开发
现有的ios和os x应用开发均使用objective-c,而objective-c是一门及其繁琐(verbose)且学习曲线比较陡峭的语言,如果swift能够提供一个同现有obj-c框架的简易互操作接口,我相信会有大量的程序员转投swift;与此同时,swift简易的语法也会带来相当数量的其它平台开发者。
总之,上一次某家大公司大张旗鼓的推出一门编程语言及其编程平台还是在2000年(微软推出c#),将近15年之后,苹果推出swift——作为开发者,我很高兴能够见证一门编程语言的诞生。
以上。
媒体评测:
一、Swift降低了开发者的使用门槛
Swift语言非常契合本届WWDC的slogan:Write the code,change the world。(写代码,改变世界)。
Swift这个新的语言集中了很多其它高级语言的影子,集成了他们的优点。它和Go、Ruby、Python等语言都有些神似。并且它的语法更加接近自然语言,使得编程的过程变得更加简单。这些变化进一步降低了苹果平台上App开发门槛,延续苹果一贯主张的用App来解决一切问题。这将是苹果生态链中重要的一个环节。
随Swift的推出的新版集成开发环境Xcode已经完全支持使用Swift。Xcode所附带的在线文档中也在原有的Objective-C内容的旁边放上了Swift的说明,可见苹果是多么重视Swift的发展。这也正好印证了前面提到的,苹果在降低自己生态链中最总要一环的门槛,这会使得苹果自身的竞争力进一步加强。
二、Swift语言还有不完善之处
目前看来,Swift还不够完善,比如支持的复杂数据结构比较有限,可以使用的第三方库也较少。但是它的出现,代表着接近自然语言语法的编程方法正在快速的发展,让大家看见一个美好的未来:每个希望编写App的人都可以很容易上手,并快速开发出相当不错的App。
当然,Swift也会带来许多局限性,如跨平台等问题等:和Objective-C一样,基于LLVM编译器的它目前是无法在Android、Windows Phone上工作。所以目前对跨平台的App开发者来说,它肯定不会是首选。并且,从逆向工程的角度来看,Swift和Objective-C共享运行时函数,让它看起来更像一个Objective-C优雅的包装。
三、是一次编程语言的革新
Swift语言中的Playground功能是一大亮点。Playground的实时编译和显示结果使得编程变得更加平民化和有趣。并且这种创新的交互式编程方法很可能会被延展到教育领域。说不定哪天大学里面枯燥乏味的语言和算法课程就被这种直观的形式所颠覆。
总体来说,Swift的前景是美好的。Swift的语法相当简单。综合了很多优秀计算机语言的优点。随着Swift语言的逐渐成熟,会赢得更多开发者的支持。
Swift 语言的基本运算符:
运算符(operator)是用于检查、更改或组合值的特殊符号或短语。例如,加法运算符(+)求两个数字的加和(用例 let i = 1 + 2)。更复杂的例子包括逻辑与(logical AND)运算符 &&(用例 if 已输入门禁密码 && 已通过视网膜扫描) 以及自增运算符 ++i,后者是将 i 存储的值加上 1的便捷写法。
Swift 支持标准 C 的大多数运算符,并改进了部分行为特性,以避免常见的编码错误。赋值运算符(=)不会返回值,这样可避免在打算使用等于运算符(==)的地方误用前者。算术运算符(+、-、*、/、% 等)会侦测并阻止值溢出,可避免处理超出可存储值域范围的数时出现意料之外的结果。如果需要支持溢出,可以选用 Swift 的溢出运算符,详见 溢出运算符。
与 C 语言不同,Swift 允许对浮点数求余(%)。Swift 还提供了两种 C 语言没有的区间运算符(a..b 与 a...b),作为表达值域范围的便捷写法。
本章讲解 Swift 中的常用运算符。高级运算符 一章涉及了 Swift 的高级运算符,并讲解了如何自定义运算符,以及让标准运算符支持自定义类型的运算。