2014年6月30日 星期一

Swift Language - The Basics

Swift 是 2014年 WWDC Apple 發佈的新語言,可想而知,未來在 iOS/OS X 上開發程式,Swift 是必學的程式語言。Apple 網站上已有相關的文件可參考,電子書可從App Store下載(Swift 系列已經有兩集:第一集 The Swift Programming Language,第二集 Using Swift with Cocoa and Objective-C) 想加入 iOS/OS X App 開發嗎?快來學習吧!

基本語法介紹

let name = "Book"
var money = 100

使用 let 來宣告常數(Constants); 使用 var 來宣告變數(Variables)。
Swift 會自動推導常數或變數的型別,所以 name 它知道是 String,而 money 是 Int。

不過你也可以直接告訴 Swift 你要宣告什麼型別(這語法英文翻成 Type annotation)

var city: String

也可以使用 Unicode 字元來當做常數或變數

var 問候 = "你好"

println(問候)
// prints "問候"


註解方式

在 C 裡有 // 和 /* .. */ 的方式,Swift 比較特別的是可以使用巢狀 /* .. */,例

/* This is comment 1 starts
/* This is comment 2 */
this  is comment1 end*/

分號

在 Swift 在每一行結束時是不用寫分號,但是你也可以加上分號,如果你想要在一行裡寫多個敍述,例


var 問候 = "你好"println(問候)

這裡要特別注意,分號後面不能有空白,不然會出現錯誤!

整數和浮點數

Swift 有 Int 和 UInt 的型別,根據長度的不同,還有 Int8, Int16, Int32, Int64, UInt8, Uint16, Uint32, Uint64。浮點數則有 Double 和 Float。

數字實字(Numeric Literials)

以下的變數都是表示10進制的10

var decimalInteger = 10
var binaryInteger = 0b1010 // 2進制前面要加 0b
var octalInteger = 0o12 // 8進制前面要加 0o
var hexadecimalInteger = 0x0a // 16進制前面加 0x

Swift 還提供了一種表示格式

var oneMillion = 1_000_000_000 // 1,000,000,000

型別別名

可利用關鍵字 typealiase 來定義型別別名,例:

typealias Uint8_number = UInt8

Uint8_number.max // 255

布林型別

Swift 的布林型別是 Bool,如果宣告的值為 true 或 false,該變數就會被推導成布林型別。

var isValid = true

var isEnabled = false

在 if 判斷式裡,要注意條件敍述的結果是判斷 true 或 false,例

let result = 1
if result {
    println("Yes")

}

上面寫法會造成 error
Playground execution failed: error: <REPL>:43:4: error: type 'Int' does not conform to protocol 'LogicValue'
if result{
  ^

正確寫法如下:

let result = 1
if result == 1 {
    println("Yes")
}

Tuple 型別

Tuple 是 Swift 特有的型別,它是一種複合值,由多個型別組合而成,寫法如下

let http404Error = (404, "Not Found")

http404Error 的型別是(Int, String), 它的值為 (404, "NotFound"); 你可自由的增加 Tuple 所使用的型別組合,(Int, Int, Int), (String, Int, Bool) 等。

你也可以直接從 Tuple 型別抓取個別的值出來 (decompose),例

let (statusCode, statusMessage) = http404Error


println(statusCode) // 404

println(statusMessage) // "Not Found"

在 decompose 時,可以使用 underscore (_),去忽略你不要的值

let (statusCode, _ ) = http404Error

Tuple 也可以用索引值來抓取值,例

println(http404Error.0) // 404

println(http404Error.1) // "Not Found"

在宣告時也可以直接名命個別元素名稱

let http200Status = (statusCode: 200, description: "OK")

println(http200Status.statusCode) // 200
println(http200Status.description) // "OK"

Tuple 其實比較適合用在暫時性的群組,如果需要一個複雜的資料結構,建議還是用 class 或 structure 的定義比較好。

Optional

在 Objective-C 和 C 裡並沒有 optional 的概念,它主要是用在變數值有可能不存在的情況。電子書上的說明如下:

An optional says:

- There is a value, and it equals x
or
- There isn't a value at all

所以一個 optional 變數有可能有值也可能沒值
電子書上的例子:

let possibleNumber = "123"
let convertedNumber = possibleNumber.toInt()
// convertedNumber is inferred to be of type "Int?", or "optional Int

因為passibleNumber有可能不是數字,造成呼叫 toInt() 時,有可能有值也可能沒值。所以toInt()回傳的是 Int?,也就是 optional Int。

當 optional 變數在 if 條件敍述時,如果 optional 有值它被當做是 true;如果沒值則它被當做是 false,這點我覺得很重要!因為前面有提到,if 條件敍述必須是 true 或 false,除了 Bool 型別變數可以直接使用之外,就剩 optional 變數可以直接判斷,不過,這只是 optional 特有的意義。

所以,我們可以這樣寫

var name: String?

if name {
    println("targetName is \(name!)")
} else {
    println("targetName doesn't exist!")

}
// prints "targetName doesn't exist!"

name 的值是 nil,所以它被當做是 false,注意到 optional 變數後面加一個驚嘆號(!),表示 Force unwrapping,如果 name 有值,則會列出 name 的值,例:

var name: String?

name = "Book"

if name {
    println("targetName is \(name!)")
else {
    println("targetName doesn't exist!")

}
// prints "targetName is Book"

這裡還有一個觀念叫,optional binding。目前我還不是很了解為何要有這個用法,猜測它是為了防止程式錯誤而存在。

上面的例子可以用 optional binding 的方式重寫

var name: String?

name = "Book"

if let actualName = name {
    println("targetName is \(actualName)")
} else {
    println("targetName doesn't exist!")

}

藉由 optional binding 的方式,在 if 敍述中,就只需要暫時常數 actualName,不需要像上面的例子,還要用加驚嘆號的方式取值。而且,name 一定是有值才會給 actualName。如果用驚嘆號取值,但是 optional 變數沒有值,是會出現 complie error 的!(我相信一定還有其他地方需要用到這樣的寫法,繼續研究!)

如果對沒有值的 optional 變數強制取值,就會出錯!

var name: String?


println(name!) // error

fatal error: Can't unwrap Optional.None
Playground execution failed: error: Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0).
The process has been left at the point where it was interrupted, use "thread return -x" to return to the state before expression evaluation.
* thread #1: tid = 0xe4efc4, 0x0000000109769d7f, queue = 'com.apple.main-thread', stop reason = EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
  * frame #0: 0x0000000109769d7f

nil

Swift 的 nil 和 Objective-C 的 nil 是不一樣的東西!Objective-C 的 nil 是不存在物件的指標;而 Swift 的 nil 不是指標,而是表示某個型別的值不存在而已。任何型別的 optional 都可以設定為 nil,而不是只有物件型別。nil 也不能被設定在非 optional 常數或變數。

Implicitly Unwrapped Optionals

最後一個和 optional 有關的觀念是 Implicitly Unwrapped Optionals。看一下電子書的例子:

let possibleString: String? = "An optional string."
println(possibleString!) // requires an exclamation mark to access its value
// prints "An optional string.

let assumedString: String! = "An implicitly unwrapped optional string."
println(assumedString)  // no exclamation mark is needed to access its value
// prints "An implicitly unwrapped optional string.

String? 是一個 optional string,要印出值需要加驚嘆號(!),String! 則是一個 implicitly unwrapped optional string,不需要加驚嘆號(!)就可以印出值。implicitly unwrapped optional 主要是用在 class 初始化;你也可以把它想成是給 optional 變數的一種權限,可以不需要加驚嘆號就可以印出 optional 的值來,如上的第二個例子。implicitly unwrapped optional 和一般正常的 optional 一樣可用 if 敍述來判斷是否有值,也可以用 optional binding 的方式來檢查,如下:

if assumedString {
    println(assumedString)
}
// prints "An implicitly unwrapped optional string.

if let definiteString = assumedString {
    println(definiteString)
}
// prints "An implicitly unwrapped optional string.

雖然如此,要注意 implicitly unwrapped optional 是一定有值存在的,如果常數或變數有可能變成 nil,那還是得用正常的 optional 來處理!



沒有留言:

張貼留言