Swift 語言最小化
swift_tour_learning-swift.jpg
在 WWDC 2014 上 Apple Duang!!! 一聲發布了 Swift 。在那次發布會上, Apple 向外界宣布了,自己其實是一家軟件公司。
2015 年, Apple 又 Duang!!! 一聲將 Swift 開源。這讓 Swift 迅速攻占了服務器,這使 Swift 開發 Backend server 成為了可能( Vapor )。
初次接觸 Swift,讓我看到了 Scala、C#、ES 6 的影子,并且語法層面兼容 Objective C。first-class functions 特性讓語言并不局限于 OO,讓 Swift 具有函數式編程語言的表達力。 同時,Swift 作者 Chris Lattner 這位傳奇人物的存在,讓 Swift 成為值得長期投資的一門語言。
變量
Swift 中可以使用 var 和 let 直接定義 變量 或 常量 。
定義變量:
?
var age = 20// 定義變量
let name = "Halo" // 定義常亮
age = 21
聲明類型:
上段代碼看起來有些類似 javascript 若類型語言的特性,Swift 本質上還是強類型的語言,聲明變量的時候,可以指定數據類型:
let cash: Float = 1.25
let money: Double = 1.252525
let dollar: String = "USD"
使用 String
對于字符串,Swift 簡化了 Objective C NSString 的定義方式: @"" :
let currencies = "AUD, " + dollar
let rmb = "1 \(dollar) is 6 RMB"
let formattedString = String(format: "%.2f \(dollar) is about 600 RMB", 100.0) // 100.00 USD is about 600 RMB
\(variable) 是 Swift 為字符串模板提供的支持。不過 Swift 還是支持類似 ES 6 或者 Ruby 中多行字符串模板。多行字符串還是需要 + 號拼接:
let introduceSwift = "We are excited by this new chapter in the story of Swift. " +
"After Apple unveiled the Swift programming language, it quickly became one of " +
"the fastest growing languages in history. Swift makes it easy to write software " +
"that is incredibly fast and safe by design. Now that Swift is open source, you can " +
"help make the best general purpose programming language available everywhere."
使用 tuple
tuple 是 Swift 引入的一種新的數據類型,它可以方便支持方法的多返回值:
let numbersTuple = (1, 100, 1000)
print("min: \(numbersTuple.0), max: \(numbersTuple.1), sum: \(numbersTuple.2)")
let numbersNamedTuple = (min: 1, max: 100, sum: 1000)
print("min: \(numbersNamedTuple.0), max: \(numbersNamedTuple.1), sum: \(numbersNamedTuple.2)")
print("min: \(numbersNamedTuple.min), max: \(numbersNamedTuple.max), sum: \(numbersNamedTuple.sum)")
Collections
創建集合:
Swift 的集合類型主要還是 Array 和 Dictionary :
var fruits = ["apple", "banana", "oranage"]
var fruitsPrice = [
"apple": 4.25,
"banana": 6.2
]
print(fruitsPrice[fruits[1]]) // 6.2
定義空集合:
var emptyArray = [String]()
var emptyDictionary = [String: Float]()
將已有集合設置為空時,可以用如下簡寫:
fruits = []
fruitsPrice = [:]
使用 for in 遍歷集合:
for score in [1,2,3,4,5,6] {
print(score * score * score)
}
for (key, val) in ["one": 1, "two": 2] {
print("\(val) is \(key)")
}
if else 和 Optional
Swift 中新增一種類型 Optional,這個概念來自 Scala。 Optional 類似一個包裝器,它可以包裝一個數值,但是 Optional 可能返回 nil ,可能返回數據。多用于錯誤處理,通常跟 if else 連用:
聲明 Optional:
var optionalString: String? = nil
//print(optionalString!) // nil 取值會報錯
print(optionalString == nil)
var optionalName: String? = "Jian"
print(optionalName!)
String? 表示一個 String 類型的 Optional。只有 Optional 可以接受 nil 值。如果對一個 nil 的 Optional 取值會報錯,一般取值前會對 Optional 做判斷:
var optionalString: String? = nil
if optionalString != nil {
let val = optionalString!
} else {
print("There is no value")
}
if-else 簡化 Optional 取值:
Swift 為上面這種方式提供一種簡寫:
if let val = optionalString {
print("There is a value: \(val)")
} else {
print("There is no value")
}
通常會將 if-else 和 Optional 這么使用:
var optionalName: String? = "Jian"
print(optionalName!)
var greeting = "Hello!"
if let name = optionalName {
greeting = "Hello \(name)"
}
Optional 默認值:
使用 ?? 可以為 Optional 提供默認值:
let fullName: String = "Jian"
let nickName: String? = nil
let displayName = "\(nickName ?? fullName)"
switch
Swift 中的 switch 強大很多,支持 String,多值匹配,條件匹配:
let vegetable = "red pepper"
switch vegetable {
case "celery":
print("Add some raisins and make ants on a log.")
case "cucumber", "watercress":
print("Taht would make a good tea sandwich.")
case let x where x.hasSuffix("pepper"):
print("Is it a spicy \(x)?") // Is it a spicy red pepper?
default:
print("Everythink tasts good")
}
使用循環
for in 循環
Swift 中的 for in 和 javascript 中的有點類似。使用 for in 便利 Dictionary:
let numbersDict = [
"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 numbersDict {
for number in numbers {
number
if number > largest {
largest = number
}
}
}
print(largest) // 25
使用 for in 遍歷 Range:
var total = 0
for i in 0..<4 {
total += i
}
print(total) // 6
while 循環
一般語言都會提供 while 和 do {} while 循環。Swift 采用 while 和 repeat {} while :
var n = 1
while n < 100 {
n += n
}
print(n) //128
var m = 1
repeat {
m += m
} while m < 100
print(m) // 128
Functions
Swift 中的函數具有 javascript 和 objective c 的雙重特征。并且函數在 Swift 中是一等公民(First-class type),具有高階函數的特性。
定義函數
一般情況下,跟 Objective C 方法一樣,需要給函數參數提供 Label:
func greet(person: String, day: String) -> String {
return "Hello \(person), today is \(day)."
}
greet(person: "Jian", day: "Friday")
使用 _ 表示省略 Label:
func greet(_ person: String, on day: String) -> String {
return "Hello \(person), today is \(day)."
}
greet("Jian", on: "Friday")
函數可以使用 tuple 返回多個值:
func calcStatistics(scores: [Int]) -> (min: Int, max: Int, sum: Int) {
var min = scores[0]
var max = scores[0]
var sum = 0
for score in scores {
if score > max {
max = score
} else if score < min {
min = score
}
sum += score
}
return (min, max, sum)
}
let statistics = calcStatistics(scores: [5, 1, 100, 30, 90])
print(statistics.sum) // 226
print(statistics.2) // 226
無限參數:
func sumOf(numbers: Int...) -> Int {
return numbers.reduce(0, +)
}
sumOf() // 0
sumOf(numbers: 1, 2, 3, 4, 10) // 20
使用 Int... 在函數的最后一個參數,表示后面可以接受無限個整數參數。
函數嵌套
func returnFifteen() -> Int {
var y = 10
func add() { y += 5 }
add()
return y
}
returnFifteen() // 15
高階函數
高階函數( high-order function ),是函數是編程的一個概念,高階函數的特點:
- 可以將函數當做返回值,即:可以使用函數創建函數
- 可以將函數當做參數接收
使用函數創建另一個函數:
func createIncrementer() -> ((Int) -> Int) {
func plusOne(number: Int) -> Int {
return 1 + number
}
return plusOne
}
let incrementer = createIncrementer()
incrementer(10)
函數作為參數:
func hasAnyMatches(_ list: [Int], matcher: (Int) -> Bool) -> Bool {
for item in list {
if matcher(item) {
return true
}
}
return false
}
func lessThanThen(number: Int) -> Bool {
return number < 10
}
hasAnyMatches([20, 10, 7, 12], matcher: lessThanThen)
Closure (閉包)
Closure 可以理解匿名函數,在很多 Callback 和集合操作中使用:
hasAnyMatches([20, 10, 7, 12]) { (item: Int) -> Bool in
item < 10
}
[20, 10, 7, 12].map { (item: Int) -> Int in
return 3 * item
}
[20, 10, 7, 12].map({ item in 3 * item })
如果省略 () 后, Closure 是唯一的參數:
let sortedNumbers = [20, 10, 7, 12].sorted { $0 > $1 }
print(sortedNumbers)
Objects and Classes
定義和使用類:
class Shape {
var numberOfSides = 0
func simpleDescription() -> String {
return "A shap with \(numberOfSides) sides."
}
}
let shape = Shape()
shape.numberOfSides = 10
shape.simpleDescription()
使用繼承:
class NamedShape : Shape {
var name: String
init(name: String) {
self.name = name
}
}
// inherit and override
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 square = Square(sideLength: 10.0, name: "Jian's Square")
square.area()
square.simpleDescription()
使用屬性
Swift 中對屬性的處理,有些像 C#。
使用 getter/setter
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 triangle with sides of length \(sideLength)"
}
}
var triangle = EquilateralTriangle(sideLength: 3.1, name: "A triangle")
print(triangle.perimeter) // 9.3
triangle.perimeter = 9.9
print(triangle.sideLength) // 3.3
使用 willSet:
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: "other shape")
print(triangleAndSquare.square.sideLength) // 10.0
print(triangleAndSquare.triangle.sideLength) // 10.0
triangleAndSquare.square = Square(sideLength: 50, name: "Large square")
print(triangleAndSquare.triangle.sideLength) // 50.0
使用 willSet 保證 square 和 triangle 的 sideLength 始終相等。
使用 Optional 類型
使用 ?. 取值,當值為 nil 時返回 nil ,而不是報錯。
let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square")
let sideLength = optionalSquare?.sideLength
let nilSquare: Square? = nil
let nilLength = nilSquare?.sideLength
Enumerations
定義 enum 類型:
enum Level: Int {
case Zero, First, Second
}
Level.Zero.rawValue
Level.First.rawValue
enum 的 rawValue 默認從 0 開始,依次遞增。
在 enum 中創建方法:
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"
}
}
}
定義特性類型的 enum:
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.rawValue)
}
}
}
let ace = Rank.ace // ace
let aceRawValue = ace.rawValue // 1
enum Rank: Int 設置 enum 的 rawValue 為 Int 。我們也可以通過 rawValue 來創建 enum :
if let convertedRank = Rank(rawValue: 3) {
let threeDescription = convertedRank.simpleDescription() // 3
}
復雜的 enum :
enum ServerResponse {
case result(String, String)
case failure(String)
}
let success = ServerResponse.result("6:00 am", "8:00 pm")
let failure = ServerResponse.failure("Out of cheese")
switch success {
case let .result(sunrise, sunset):
print("Sunrise is at \(sunrise) and sunset is at \(sunset)") // Sunrise is at 6:00 am and sunset is at 8:00 pm
case let .failure(message):
print("Failure ... \(message)")
}
Structs
struct Card {
var rank: Rank
var suit: Suit
func simpleDescript() -> String {
return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
}
}
let threeOfSpades = Card(rank: .three, suit: .spades) // Card
print(threeOfSpades.simpleDescript()) // The 3 of spades
struct 和 class 最重要的區別是:
- struct 傳遞值,始終傳遞 copy
- class 傳遞引用。
Protocol
protocol ExampleProtocol {
var simpleDescription: String { get }
mutating func adjust()
}
Protocol 與 Java 中的 Interface 概念類似。在 Swift 中,class、struct、enum、extension 都可以實現 Protocol:
class 實現 protocol:
class SimpleClass: ExampleProtocol {
var simpleDescription: String = "A simple class."
var moreProperty: Int = 315
func adjust() {
simpleDescription += " Now 100% adjusted"
}
}
var simpleClass = SimpleClass()
simpleClass.adjust()
print(simpleClass.simpleDescription) // A simple class. Now 100% adjusted
struct 實現 protocol:
struct SimpleStructure: ExampleProtocol {
var simpleDescription: String = "A simple structure"
mutating func adjust() {
simpleDescription += " (adjusted) "
}
}
var simpleStruct = SimpleStructure()
simpleStruct.adjust()
print(simpleStruct.simpleDescription)
mutating 修飾符表示,當前方法在 struct 中可以修改 struct 的值。
在 protocol 的應用中,可以使用 Java 中面向 Interface 編程:
let protocolValue: ExampleProtocol = simpleStruct
print(protocolValue.simpleDescription) // A simple structure (adjusted)
Extensions
Swift 中的 extension 和 ruby 中的 Open Class 概念很像,在 ObjC 中是 Category 。它可以為已有類型添加新的特性:
extension Int: ExampleProtocol {
var simpleDescription: String {
return "The number \(self)"
}
mutating func adjust() {
self += 10
}
}
print(7.simpleDescription)
Error Handling
throws 異常
enum PointerError: Error {
case outOfPaper
case noToner
case onFire
}
// throw error
func send(job: Int, toPointer printerName: String) throws -> String {
if printerName == "Never has toner" {
throw PointerError.noToner
}
return "Job sent"
}
catch 和處理異常
對于具有 throws 聲明的方法,需要使用 try 關鍵字調用,然后使用 do {} catch {} 包裹:
do {
let pointerResp = try send(job: 1024, toPointer: "Never has toner")
print(pointerResp)
} catch { // catch all errors
print(error) // use error by default
}
處理多個異常:
do {
let pointerResponse = try send(job: 1024, toPointer: "Jian")
print(pointerResponse)
throw PointerError.onFire
} catch PointerError.onFire {
print("I'll just put shi over here, with the result of the fire.") // I'll just put shi over here, with the result of the fire.
} catch let pointerError as PointerError {
print("Printer error: \(pointerError) .")
} catch {
print(error)
}
通常 catch 多個 Error 時, catch 順序需要從小異常,到范圍更大的異常。
使用 try?
// try? -> Optional
let pointerFailure = try? send(job: 1024, toPointer: "Never has toner") // nil
let pointerSuccess = try? send(job: 2048, toPointer: "Good pointer") // Job sent
使用 defer
在方法 throws 時,會終端當前函數后續的代碼執行,使用 defer 可以確保 defer 代碼段中的代碼在函數返回前始終被執行。這個概念有些像 Java 的 try {} catch {} finally {} 中的 finally :
func ensureExecute() throws -> String {
defer {
print("Complete")
}
do {
try send(job: 1024, toPointer: "Never has toner")
} catch {
throw error
}
return "Executed"
}
let executed = try? ensureExecute() // Complete
Generic
Swift 開始支持泛型(Generic):
enum OptionalValue<Wrapped> {
case none
case some(Wrapped)
}
var possibleInteger: OptionalValue<Int> = .none // none
possibleInteger = .some(100) // some(100)
使用 where 限定泛型的類型:
func anyCommonElements<T: Sequence, U: Sequence>(_ lhs: T, _ rhs: U) -> Bool
where T.Iterator.Element: Equatable, T.Iterator.Element == U.Iterator.Element {
for lhsItem in lhs {
for rhsItem in rhs {
if lhsItem == rhsItem {
return true
}
}
}
return false
}
anyCommonElements([1,2,3,4,5], [5])
where T.Iterator.Element: Equatable, T.Iterator.Element == U.Iterator.Element 限制 T 和 U 中的元素,必須實現 Equatable ,并且 T 和 U 中的元素是同一種類型。
來自:http://www.jianshu.com/p/3d8963cdb0b9