swift是什么?
swift是蘋果于wwdc 2014發(fā)布的編程語言,這里引用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程序。(估計也不會支持其它屌絲系統(tǒng))
swift吸取了c和objective-c的優(yōu)點,且更加強大易用。
swift可以使用現(xiàn)有的cocoa和cocoa touch框架。
swift兼具編譯語言的高性能(performance)和腳本語言的交互性(interactive)。
swift語言概覽
基本概念
注:這一節(jié)的代碼源自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
類型推導(dǎo)
swift支持類型推導(dǎo)(type inference),所以上面的代碼不需指定類型,如果需要指定類型:
1
let explicitdouble : double = 70
swift不支持隱式類型轉(zhuǎn)換(implicitly casting),所以下面的代碼需要顯式類型轉(zhuǎn)換(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."
數(shù)組和字典
swift使用[]操作符聲明數(shù)組(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)語法創(chuàng)建空數(shù)組和空字典:
1
2
let emptyarray = string[]()
let emptydictionary = dictionary< string float> ()
如果類型信息已知,則可以使用[]聲明空數(shù)組,使用[:]聲明空字典。
控制流
概覽
swift的條件語句包含if和switch,循環(huán)語句包含for-in、for、while和do-while,循環(huán)/判斷條件不需要括號,但循環(huán)/判斷體(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
}
}
可空類型
結(jié)合if和let,可以方便的處理可空變量(nullable variable)。對于空值,需要在類型聲明后添加?顯式標(biāo)明該類型可空。
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."
}
其它循環(huán)
for-in除了遍歷數(shù)組也可以用來遍歷字典:
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循環(huán)和do-while循環(huán):
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支持傳統(tǒng)的for循環(huán),此外也可以通過結(jié)合..(生成一個區(qū)間)和for-in實現(xiàn)同樣的邏輯。
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除了..還有...:..生成前閉后開的區(qū)間,而...生成前閉后閉的區(qū)間。
函數(shù)和閉包
函數(shù)
swift使用func關(guān)鍵字聲明函數(shù):
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()
支持帶有變長參數(shù)的函數(shù):
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)
函數(shù)也可以嵌套函數(shù):
1
2
3
4
5
6
7
8
9
func returnfifteen() -> int {
var y = 10
func add() {
y += 5
}
add()
return y
}
returnfifteen()
作為頭等對象,函數(shù)既可以作為返回值,也可以作為參數(shù)傳遞:
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)
閉包
本質(zhì)來說,函數(shù)是特殊的閉包,swift中可以利用{}聲明匿名閉包:
1
2
3
4
5
numbers.map({
(number: int) -> int in
let result = 3 number
return result
})
當(dāng)閉包的類型已知時,可以使用下面的簡化寫法:
1
numbers.map({ number in 3 number })
此外還可以通過參數(shù)的位置來使用參數(shù),當(dāng)函數(shù)最后一個參數(shù)是閉包時,可以使用下面的語法:
1
sort([1 5 3 12 2]) { $0 > $1 }
類和對象
創(chuàng)建和使用類
swift使用class創(chuàng)建一個類,類可以包含字段和方法:
1
2
3
4
5
6
class shape {
var numberofsides = 0
func simpledescription() -> string {
return " a shape with \(numberofsides) sides."
}
}
創(chuàng)建shape類的實例,并調(diào)用其字段和方法。
1
2
3
var shape = shape()
shape.numberofsides = 7
var shapedescription = shape.simpledescription()
通過init構(gòu)建對象,既可以使用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進行清理工作。
繼承和多態(tài)
swift支持繼承和多態(tài)(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方法沒有被標(biāo)識為override,則會引發(fā)編譯錯誤。
屬性
為了簡化代碼,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的構(gòu)造器進行了如下操作:
為子類型的屬性賦值。
調(diào)用父類型的構(gòu)造器。
修改父類型的屬性。
如果不需要計算屬性的值,但需要在賦值前后進行一些操作的話,使用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。
調(diào)用方法
swift中,函數(shù)的參數(shù)名稱只能在函數(shù)內(nèi)部使用,但方法的參數(shù)名稱除了在內(nèi)部使用外還可以在外部使用(第一個參數(shù)除外),例如:
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支持為方法參數(shù)取別名:在上面的代碼里,numberoftimes面向外部,times面向內(nèi)部。
?的另一種用途
使用可空值時,?可以出現(xiàn)在方法、屬性或下標(biāo)前面。如果?前的值為nil,那么?后面的表達式會被忽略,而原表達式直接返回nil,例如:
1
2
3
let optionalsquare: square? = square(sidelength: 2.5 name: " optional
square" )
let sidelength = optionalsquare?.sidelength
當(dāng)optionalsquare為nil時,sidelength屬性調(diào)用會被忽略。
枚舉和結(jié)構(gòu)
枚舉
使用enum創(chuàng)建枚舉——注意swift的枚舉可以關(guān)聯(lián)方法:
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)數(shù)值和枚舉值之間進行轉(zhuǎn)換:
1
2
3
if let convertedrank = rank.fromraw(3) {
let threedescription = convertedrank.simpledescription()
}
注意枚舉中的成員值(member value)是實際的值(actual value),和原始值(raw value)沒有必然關(guān)聯(lián)。
一些情況下枚舉不存在有意義的原始值,這時可以直接忽略原始值:
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()
除了可以關(guān)聯(lián)方法,枚舉還支持在其成員上關(guān)聯(lián)值,同一枚舉的不同成員可以有不同的關(guān)聯(lián)的值:
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)"
}
結(jié)構(gòu)
swift使用struct關(guān)鍵字創(chuàng)建結(jié)構(gòu)。結(jié)構(gòu)支持構(gòu)造器和方法這些類的特性。結(jié)構(gòu)和類的最大區(qū)別在于:結(jié)構(gòu)的實例按值傳遞(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()
協(xié)議(protocol)和擴展(extension)
協(xié)議
swift使用protocol定義協(xié)議:
1
2
3
4
protocol exampleprotocol {
var simpledescription: string { get }
mutating func adjust()
}
類型、枚舉和結(jié)構(gòu)都可以實現(xiàn)(adopt)協(xié)議:
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
擴展
擴展用于在已有的類型上增加新的功能(比如新的方法或?qū)傩裕,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使用< > 來聲明泛型函數(shù)或泛型類型:
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也支持在類、枚舉和結(jié)構(gòu)中使用泛型:
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),比如需求某個泛型類型實現(xiàn)某個接口或繼承自某個特定類型、兩個泛型類型屬于同一個類型等等,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#。
格式風(fēng)格與go相仿(沒有句末的分號,判斷條件不需要括號)。
python風(fēng)格的當(dāng)前實例引用語法(使用self)和列表字典聲明語法。
haskell風(fēng)格的區(qū)間聲明語法(比如1..3,1...3)。
協(xié)議和擴展源自objective-c(自家產(chǎn)品隨便用)。
枚舉類型很像java(可以擁有成員或方法)。
class和struct的概念和c#極其相似。
注意這里不是說swift是抄襲——實際上編程語言能玩的花樣基本就這些,況且swift選的都是在我看來相當(dāng)不錯的特性。
而且,這個大雜燴有一個好處——就是任何其它編程語言的開發(fā)者都不會覺得swift很陌生——這一點很重要。
拒絕隱式(refuse implicity)
swift去除了一些隱式操作,比如隱式類型轉(zhuǎn)換和隱式方法重載這兩個坑,干的漂亮。
swift的應(yīng)用方向
我認為swift主要有下面這兩個應(yīng)用方向:
教育
我指的是編程教育,F(xiàn)有編程語言最大的問題就是交互性奇差,從而導(dǎo)致學(xué)習(xí)曲線陡峭。相信swift及其交互性極強的編程環(huán)境能夠打破這個局面,讓更多的人——尤其是青少年,學(xué)會編程。
這里有必要再次提到brec victor的inventing on principle,看了這個視頻你就會明白一個交互性強的編程環(huán)境能夠帶來什么。
應(yīng)用開發(fā)
現(xiàn)有的ios和os x應(yīng)用開發(fā)均使用objective-c,而objective-c是一門及其繁瑣(verbose)且學(xué)習(xí)曲線比較陡峭的語言,如果swift能夠提供一個同現(xiàn)有obj-c框架的簡易互操作接口,我相信會有大量的程序員轉(zhuǎn)投swift;與此同時,swift簡易的語法也會帶來相當(dāng)數(shù)量的其它平臺開發(fā)者。
總之,上一次某家大公司大張旗鼓的推出一門編程語言及其編程平臺還是在2000年(微軟推出c#),將近15年之后,蘋果推出swift——作為開發(fā)者,我很高興能夠見證一門編程語言的誕生。
以上。
媒體評測:
一、Swift降低了開發(fā)者的使用門檻
Swift語言非常契合本屆WWDC的slogan:Write the code,change the world。(寫代碼,改變世界)。
Swift這個新的語言集中了很多其它高級語言的影子,集成了他們的優(yōu)點。它和Go、Ruby、Python等語言都有些神似。并且它的語法更加接近自然語言,使得編程的過程變得更加簡單。這些變化進一步降低了蘋果平臺上App開發(fā)門檻,延續(xù)蘋果一貫主張的用App來解決一切問題。這將是蘋果生態(tài)鏈中重要的一個環(huán)節(jié)。
隨Swift的推出的新版集成開發(fā)環(huán)境Xcode已經(jīng)完全支持使用Swift。Xcode所附帶的在線文檔中也在原有的Objective-C內(nèi)容的旁邊放上了Swift的說明,可見蘋果是多么重視Swift的發(fā)展。這也正好印證了前面提到的,蘋果在降低自己生態(tài)鏈中最總要一環(huán)的門檻,這會使得蘋果自身的競爭力進一步加強。
二、Swift語言還有不完善之處
目前看來,Swift還不夠完善,比如支持的復(fù)雜數(shù)據(jù)結(jié)構(gòu)比較有限,可以使用的第三方庫也較少。但是它的出現(xiàn),代表著接近自然語言語法的編程方法正在快速的發(fā)展,讓大家看見一個美好的未來:每個希望編寫App的人都可以很容易上手,并快速開發(fā)出相當(dāng)不錯的App。
當(dāng)然,Swift也會帶來許多局限性,如跨平臺等問題等:和Objective-C一樣,基于LLVM編譯器的它目前是無法在Android、Windows Phone上工作。所以目前對跨平臺的App開發(fā)者來說,它肯定不會是首選。并且,從逆向工程的角度來看,Swift和Objective-C共享運行時函數(shù),讓它看起來更像一個Objective-C優(yōu)雅的包裝。
三、是一次編程語言的革新
Swift語言中的Playground功能是一大亮點。Playground的實時編譯和顯示結(jié)果使得編程變得更加平民化和有趣。并且這種創(chuàng)新的交互式編程方法很可能會被延展到教育領(lǐng)域。說不定哪天大學(xué)里面枯燥乏味的語言和算法課程就被這種直觀的形式所顛覆。
總體來說,Swift的前景是美好的。Swift的語法相當(dāng)簡單。綜合了很多優(yōu)秀計算機語言的優(yōu)點。隨著Swift語言的逐漸成熟,會贏得更多開發(fā)者的支持。
Swift 語言的基本運算符:
運算符(operator)是用于檢查、更改或組合值的特殊符號或短語。例如,加法運算符(+)求兩個數(shù)字的加和(用例 let i = 1 + 2)。更復(fù)雜的例子包括邏輯與(logical AND)運算符 &&(用例 if 已輸入門禁密碼 && 已通過視網(wǎng)膜掃描) 以及自增運算符 ++i,后者是將 i 存儲的值加上 1的便捷寫法。
Swift 支持標(biāo)準(zhǔn) C 的大多數(shù)運算符,并改進了部分行為特性,以避免常見的編碼錯誤。賦值運算符(=)不會返回值,這樣可避免在打算使用等于運算符(==)的地方誤用前者。算術(shù)運算符(+、-、*、/、% 等)會偵測并阻止值溢出,可避免處理超出可存儲值域范圍的數(shù)時出現(xiàn)意料之外的結(jié)果。如果需要支持溢出,可以選用 Swift 的溢出運算符,詳見 溢出運算符。
與 C 語言不同,Swift 允許對浮點數(shù)求余(%)。Swift 還提供了兩種 C 語言沒有的區(qū)間運算符(a..b 與 a...b),作為表達值域范圍的便捷寫法。
本章講解 Swift 中的常用運算符。高級運算符 一章涉及了 Swift 的高級運算符,并講解了如何自定義運算符,以及讓標(biāo)準(zhǔn)運算符支持自定義類型的運算。