關於
這篇文章簡要介紹了蘋果於WWDC 2014釋出的程式語言——Swift。
前言
在這裡我認為有必要提一下Brec Victor的Inventing on Principle,Swift程式設計環境的大部分概念都源自於Brec這個演講。
接下來進入正題。
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——作為開發者,我很高興能夠見證一門程式語言的誕生。