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()
}
一些情況下枚舉不存在有意義的原始值,這時可以直接忽略原始值:
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 的高級運算符,並講解了如何自定義運算符,以及讓標准運算符支持自定義類型的運算。