Collection Types
Swift 語言提供Arrays、Sets和Dictionaries三種基本的集合類型用來存儲集合數據。數組(Arrays)是有序數據的集。集合(Sets)是無序無重複數據的集。字典(Dictionaries)是無序的鍵值對的集。
Arrays
Arrays使用有序列表存儲同一類型的多個值。相同的值可以多次出現在一個數組的不同位置中。
The type of a Swift array is written in full as Array, where Element is the type of values the array is allowed to store.
Note that the type of the someInts variable is inferred to be [Int] from the type of the initializer.
ex. Creating an Empty Array:
var someInts = [Int]()
print("someInts is of type [Int] with \(someInts.count) items.")
// prints "someInts is of type [Int] with 0 items."
someInts.append(3)
// someInts 現在包含一個 Int 值
someInts = []
// someInts 現在是空數組,但是仍然是[Int] 類型的。
ex. Creating an Array with a Default Value
Pass this initializer the number of items to be added to the new array (called count) and a default value of the appropriate type (called repeatedValue):
var threeDoubles = [Double](count: 3, repeatedValue: 0.0)
// threeDoubles is of type [Double], and equals [0.0, 0.0, 0.0]
//Creating an Array by Adding Two Arrays Together
var anotherThreeDoubles = [Double](count: 3, repeatedValue: 2.5) // [2.5, 2.5, 2.5]
var sixDoubles = threeDoubles + anotherThreeDoubles
// sixDoubles is inferred as [Double], and equals [0.0, 0.0, 0.0, 2.5, 2.5, 2.5]
ex. Creating an Array with an Array Literal
var shoppingList: [String] = ["Eggs", "Milk"]
// shoppingList has been initialized with two initial items
for item in shoppingList {
print(item)
}
// Eggs
// Milk
enumerate()
返回一個由每一個數據項索引值和數據值組成的元組。
for (index, value) in shoppingList.enumerate() {
print("Item \(index + 1): \(value)")
}
// Item 1: Eggs
// Item 2: Milk
Sets
Set用來存儲相同類型並且沒有確定順序的值。當集合元素順序不重要時或者希望確保每個元素只出現一次時可以使用集合而不是數組。
Swift’s Set type is bridged to Foundation’s NSSet class.
Hash Values for Set Types
A type must be hashable in order to be stored in a set—that is, the type must provide a way to compute a hash value for itself. A hash value is an Int value that is the same for all objects that compare equally, such that if a == b, it follows that a.hashValue == b.hashValue
.
Set Type Syntax
Swift 中的Set類型被寫為Set,這裡的Element表示Set中允許存儲的類型,和數組不同的是,集合沒有等價的簡化形式。
ex. Creating and Initializing an Empty Set
var letters = Set<Character>()
print("letters is of type Set<Character> with \(letters.count) items.")
// prints "letters is of type Set<Character> with 0 items."
letters.insert("a")
// letters now contains 1 value of type Character
letters = []
// letters is now an empty set, but is still of type Set<Character>
ex. Creating a Set with an Array Literal
var favoriteGenres: Set<String> = ["Rock", "Classical", "Hip hop"]
// favoriteGenres has been initialized with three initial items
Accessing and Modifying a Set
print("I have \(favoriteGenres.count) favorite music genres.")
// prints "I have 3 favorite music genres."
if favoriteGenres.isEmpty {
print("As far as music goes, I'm not picky.")
} else {
print("I have particular music preferences.")
}
// prints "I have particular music preferences."
a. Add a new item into a set by calling the set’s insert(_:) method.
b. Remove an item from a set by calling the set’s remove(_:) method.
c. To check whether a set contains a particular item, use the contains(_:) method.
Fundamental Set Operations
The illustration below depicts two sets–a and b– with the results of various set operations represented by the shaded regions.
a. 使用intersect(_:)方法根據兩個集合中都包含的值創建的一個新的集合。
b. 使用exclusiveOr(_:)方法根據在一個集合中但不在兩個集合中的值創建一個新的集合。
c. 使用union(_:)方法根據兩個集合的值創建一個新的集合。
d. 使用subtract(_:)方法根據不在該集合中的值創建一個新的集合。
let oddDigits: Set = [1, 3, 5, 7, 9]
let evenDigits: Set = [0, 2, 4, 6, 8]
let singleDigitPrimeNumbers: Set = [2, 3, 5, 7]
oddDigits.union(evenDigits).sort()
// [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
oddDigits.intersect(evenDigits).sort()
// []
oddDigits.subtract(singleDigitPrimeNumbers).sort()
// [1, 9]
oddDigits.exclusiveOr(singleDigitPrimeNumbers).sort()
// [1, 2, 9]
Set Membership and Equality
let houseAnimals: Set = ["dog", "cat"]
let farmAnimals: Set = ["cow", "chicken", "Sheep", "dog", "cat"]
let cityAnimals: Set = ["pigeon", "rat"]
houseAnimals.isSubsetOf(farmAnimals)
// true
farmAnimals.isSupersetOf(houseAnimals)
// true
farmAnimals.isDisjointWith(cityAnimals)
// true
Dictionaries
字典是一種存儲多個相同類型的值的容器。每個值(value)都關聯唯一的key.
Swift’s Dictionary type is bridged to Foundation’s NSDictionary class.
Dictionary Type Shorthand Syntax
Swift 的字典使用Dictionary<Key, Value>
定義,其中Key是字典中鍵的數據類型,Value是字典中對應於這些鍵所存儲值的數據類型。也可以用[Key: Value]怎樣快捷的形式去創建一個字典類型。
Creating a Dictionary
var namesOfIntegers = [Int: String]()
// namesOfIntegers is an empty [Int: String] dictionary
namesOfIntegers[16] = "sixteen"
// namesOfIntegers now contains 1 key-value pair
namesOfIntegers = [:]
// namesOfIntegers is once again an empty dictionary of type [Int: String]
一個鍵值對是一個key和一個value的結合體。在字典字面量中,每一個鍵值對的鍵和值都由冒號分割。這些鍵值對構成一個列表,其中這些鍵值對由方括號包含、由逗號分割:
[key 1: value 1, key 2: value 2, key 3: value 3]
var airports: [String: String] = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
也可以使用以下宣告方式,Swift 可以推斷出Dictionary<String, String>
是airports字典的正確類型。
var airports = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
Accessing and Modifying a Dictionary
大部分的用法同上述,The updateValue(_:forKey:) method returns an optional value of the dictionary’s value type.remove ValueForKey(_:)
方法也可以用來在字典中移除鍵值對。這個方法在鍵值對存在的情況下會移除該鍵值對並且返回被移除的值或者在沒有值的情況下返回nil:
if let oldValue = airports.updateValue("Dublin Airport", forKey: "DUB") {
print("The old value for DUB was \(oldValue).")
}
// prints "The old value for DUB was Dublin."
if let removedValue = airports.removeValueForKey("DUB") {
print("The removed airport's name is \(removedValue).")
} else {
print("The airports dictionary does not contain a value for DUB.")
}
// prints "The removed airport's name is Dublin Airport."
FOR-IN method 1.
for (airportCode, airportName) in airports {
print("\(airportCode): \(airportName)")
}
// YYZ: Toronto Pearson
// LHR: London Heathrow
Method 2.
for airportCode in airports.keys {
print("Airport code: \(airportCode)")
}
// Airport code: YYZ
// Airport code: LHR
for airportName in airports.values {
print("Airport name: \(airportName)")
}
// Airport name: Toronto Pearson
// Airport name: London Heathrow
Forloop
Swift 提供兩種for循環形式以來按照指定的次數多次執行一系列語句:
- for-in循環對一個集合裡面的每個元素執行一系列語句。
- for 循環,用來重複執行一系列語句直到達成特定條件達成,一般通過在每次循環完成後增加計數器的值來實現。
For-In
Example:
for index in 1...5 {
print("\(index) times 5 is \(index * 5)")
}
// 1 times 5 is 5
// 2 times 5 is 10
// 3 times 5 is 15
// 4 times 5 is 20
// 5 times 5 is 25
如果不需要知道區間序列內每一項的值,你可以使用下劃線(_)
替代變量名來忽略對值的訪問:
let base = 3
let power = 10
var answer = 1
for _ in 1...power {
answer *= base
}
print("\(base) to the power of \(power) is \(answer)")
// prints "3 to the power of 10 is 59049"
let numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
for (animalName, legCount) in numberOfLegs {
print("\(animalName)s have \(legCount) legs")
}
// ants have 6 legs
// cats have 4 legs
// spiders have 8 legs
Swift supports traditional C-style for loops with a condition and an incrementer:
for var index = 0; index < 3; ++index {
print("index is \(index)")
}
// index is 0
// index is 1
// index is 2
While Loops
while循環運行一系列語句直到條件變成false。這類循環適合使用在第一次迭代前迭代次數未知的情況下。 Swift 提供兩種while循環形式:
- while循環,每次在循環開始時計算條件是否符合;
- repeat-while循環,每次在循環結束時計算條件是否符合。
while循環從計算單一條件開始。如果條件為true,會重複運行一系列語句,直到條件變為false。
while condition {
statements
}
var square = 0
var diceRoll = 0
while square < finalSquare {
// roll the dice
if ++diceRoll == 7 { diceRoll = 1 }
// move by the rolled amount
square += diceRoll
if square < board.count {
// if we're still on the board, move up or down for a snake or a ladder
square += board[square]
}
}
while循環的另外一種形式是repeat-while,它和while的區別是在判斷循環條件之前,先執行一次循環的代碼塊,然後重複循環直到條件為false。
The
repeat-while loop
in Swift is analogous to a do-while loop in other languages.
repeat {
statements
} while condition
repeat {
// move up or down for a snake or ladder
square += board[square]
// roll the dice
if ++diceRoll == 7 { diceRoll = 1 }
// move by the rolled amount
square += diceRoll
} while square < finalSquare
print("Game over!")
Conditional Statements
if-else
temperatureInFahrenheit = 90
if temperatureInFahrenheit <= 32 {
print("It's very cold. Consider wearing a scarf.")
} else if temperatureInFahrenheit >= 86 {
print("It's really warm. Don't forget to wear sunscreen.")
} else {
print("It's not that cold. Wear a t-shirt.")
}
// prints "It's really warm. Don't forget to wear sunscreen."
Switch
switch語句會嘗試把某個值與若干個模式(pattern)進行匹配。根據第一個匹配成功的模式,switch語句會執行對應的代碼。當有可能的情況較多時,通常用switch語句替換if語句。
No Implicit Fallthrough
與C 語言和Objective-C 中的switch語句不同,在Swift 中,當匹配的case 分支中的代碼執行完畢後,程序會終止switch語句,而不會繼續執行下一個case 分支。這也就是說,不需要在case 分支中顯式地使用break語句。這使得switch語句更安全、更易用,也避免了因忘記寫break語句而產生的錯誤。
Although break is not required in Swift, you can still use a break statement to match and ignore a particular case, or to break out of a matched case before that case has completed its execution.
let anotherCharacter: Character = "a"
switch anotherCharacter {
case "a":
case "A":
print("The letter A")
default:
print("Not the letter A")
}
// this will report a compile-time error
case 分支的模式也可以是一個值的區間。
let approximateCount = 62
let countedThings = "moons orbiting Saturn"
var naturalCount: String
switch approximateCount {
case 0:
naturalCount = "no"
case 1..<5:
naturalCount = "a few"
case 5..<12:
naturalCount = "several"
case 12..<100:
naturalCount = "dozens of"
case 100..<1000:
naturalCount = "hundreds of"
default:
naturalCount = "many"
}
print("There are \(naturalCount) \(countedThings).")
// prints "There are dozens of moons orbiting Saturn."
使用Tuple在同一個switch語句中測試多個值。Tuple中的元素可以是值,也可以是區間。另外,使用下劃線(_)來匹配所有可能的值。
let somePoint = (1, 1)
switch somePoint {
case (0, 0):
print("(0, 0) is at the origin")
case (_, 0):
print("(\(somePoint.0), 0) is on the x-axis")
case (0, _):
print("(0, \(somePoint.1)) is on the y-axis")
case (-2...2, -2...2):
print("(\(somePoint.0), \(somePoint.1)) is inside the box")
default:
print("(\(somePoint.0), \(somePoint.1)) is outside of the box")
}
// prints "(1, 1) is inside the box"
Where
case 分支的模式可以使用where語句來判斷額外的條件。
let yetAnotherPoint = (1, -1)
switch yetAnotherPoint {
case let (x, y) where x == y:
print("(\(x), \(y)) is on the line x == y")
case let (x, y) where x == -y:
print("(\(x), \(y)) is on the line x == -y")
case let (x, y):
print("(\(x), \(y)) is just some arbitrary point")
}
// prints "(1, -1) is on the line x == -y"
Control Transfer Statements
- continue語句告訴一個循環體立刻停止本次循環迭代,重新開始下次循環迭代。就好像在說“本次循環迭代我已經執行完了”,但是並不會離開整個循環體。
let puzzleInput = "great minds think alike"
var puzzleOutput = ""
for character in puzzleInput.characters {
switch character {
case "a", "e", "i", "o", "u", " ":
continue
default:
puzzleOutput.append(character)
}
}
print(puzzleOutput)
// prints "grtmndsthnklk"
break語句會立刻結束整個控制流的執行。
當在一個循環體中使用break時,會立刻中斷該循環體的執行,然後跳轉到表示循環體結束的大括號(})後的第一行代碼。不會再有本次循環迭代的代碼被執行,也不會再有下次的循環迭代產生。Fallthrough
這個例子定義了一個String類型的變量description並且給它設置了一個初始值。函數使用switch邏輯來判斷integerToDescribe變量的值。當integerToDescribe的值屬於列表中的質數之一時,該函數添加一段文字在description後,來表明這個是數字是一個質數。然後它使用fallthrough關鍵字來“貫穿”到default分支中。 default分支添加一段額外的文字在description的最後,至此switch代碼塊執行完了。
let integerToDescribe = 5
var description = "The number \(integerToDescribe) is"
switch integerToDescribe {
case 2, 3, 5, 7, 11, 13, 17, 19:
description += " a prime number, and also"
fallthrough
default:
description += " an integer."
}
print(description)
// prints "The number 5 is a prime number, and also an integer."
The fallthrough keyword does not check the case conditions for the switch case that it causes execution to fall into. The fallthrough keyword simply causes code execution to move directly to the statements inside the next case (or default case) block, as in C’s standard switch statement behavior.
- Early Exit
像if語句一樣,guard的執行取決於一個表達式的 Boolean value。一個guard語句總是有一個else分句,如果條件不為真則執行else分句中的代碼。
func greet(person: [String: String]) {
guard let name = person["name"] else {
return
}
print("Hello \(name)!")
guard let location = person["location"] else {
print("I hope the weather is nice near you.")
return
}
print("I hope the weather is nice in \(location).")
}
greet(["name": "John"])
// prints "Hello John!"
// prints "I hope the weather is nice near you."
greet(["name": "Jane", "location": "Cupertino"])
// prints "Hello Jane!"
// prints "I hope the weather is nice in Cupertino."
Checking API Availability
Swift has built-in support for checking API availability, which ensures that you don’t accidentally use APIs that are unavailable on a given deployment target.
if #available(iOS 9, OSX 10.10, *) {
// Use iOS 9 APIs on iOS, and use OS X v10.10 APIs on OS X
} else {
// Fall back to earlier iOS and OS X APIs
}
Defining and Calling Functions
在下面例子中的函數叫做”sayHello(_:)”,這個函數用一個人的名字當做輸入,並返回給這個人的問候語。為了完成這個任務,你定義一個輸入參數-一個叫做personName 的String 值,和一個包含給這個人問候語的String 類型的返回值:
func sayHello(personName: String) -> String {
let greeting = "Hello, " + personName + "!"
return greeting
}
print(sayHello("Anna"))
// prints "Hello, Anna!"
Functions Without Parameters
儘管這個函數沒有參數,但是定義中在函數名後還是需要一對圓括號。當被調用時,也需要在函數名後寫一對圓括號。
func sayHelloWorld() -> String {
return "hello, world"
}
print(sayHelloWorld())
// prints "hello, world"
Functions With Multiple Parameters
func sayHello(personName: String, alreadyGreeted: Bool) -> String {
if alreadyGreeted {
return sayHelloAgain(personName)
} else {
return sayHello(personName)
}
}
print(sayHello("Tim", alreadyGreeted: true))
// prints "Hello again, Tim!"
Functions Without Return Values
func printAndCount(stringToPrint: String) -> Int {
print(stringToPrint)
return stringToPrint.characters.count
}
func printWithoutCounting(stringToPrint: String) {
printAndCount(stringToPrint)
}
printAndCount("hello, world")
// prints "hello, world" and returns a value of 12
printWithoutCounting("hello, world")
// prints "hello, world" but does not return a value
Functions with Multiple Return Values
You can use a tuple type as the return type for a function to return multiple values as part of one compound return value.
func minMax(array: [Int]) -> (min: Int, max: Int) {
var currentMin = array[0]
var currentMax = array[0]
for value in array[1..<array.count] {
if value < currentMin {
currentMin = value
} else if value > currentMax {
currentMax = value
}
}
return (currentMin, currentMax)
}
Optional Tuple Return Types
如果函數返回的元組類型有可能整個元組都“沒有值”,你可以使用可選的(Optional) 元組返回類型反映整個元組可以是nil的事實。
func minMax(array: [Int]) -> (min: Int, max: Int)? {
if array.isEmpty { return nil }
var currentMin = array[0]
var currentMax = array[0]
for value in array[1..<array.count] {
if value < currentMin {
currentMin = value
} else if value > currentMax {
currentMax = value
}
}
return (currentMin, currentMax)
}
if let bounds = minMax([8, -6, 2, 109, 3, 71]) {
print("min is \(bounds.min) and max is \(bounds.max)")
}
// prints "min is -6 and max is 109"
Specifying External Parameter Names
func sayHello(to person: String, and anotherPerson: String) -> String {
return "Hello \(person) and \(anotherPerson)!"
}
print(sayHello(to: "Bill", and: "Ted"))
// prints "Hello Bill and Ted!"
Default Parameter Values
func someFunction(parameterWithDefault: Int = 12) {
// function body goes here
// if no arguments are passed to the function call,
// value of parameterWithDefault is 12
}
someFunction(6) // parameterWithDefault is 6
someFunction() // parameterWithDefault is 12
Variadic Parameters
一個可變參數(variadic parameter)可以接受零個或多個值。函數調用時,你可以用可變參數來指定函數參數可以被傳入不確定數量的輸入值。通過在變量類型名後面加入(…)的方式來定義可變參數。
A function may have at most one variadic parameter.
func arithmeticMean(numbers: Double...) -> Double {
var total: Double = 0
for number in numbers {
total += number
}
return total / Double(numbers.count)
}
arithmeticMean(1, 2, 3, 4, 5)
// returns 3.0, which is the arithmetic mean of these five numbers
arithmeticMean(3, 8.25, 18.75)
// returns 10.0, which is the arithmetic mean of these three numbers
Constant and Variable Parameters
Function parameters are constants by default. Trying to change the value of a function parameter from within the body of that function results in a compile-time error.
Define variable parameters by prefixing the parameter name with the var keyword:
func alignRight(var string: String, totalLength: Int, pad: Character) -> String {
let amountToPad = totalLength - string.characters.count
if amountToPad < 1 {
return string
}
let padString = String(pad)
for _ in 1...amountToPad {
string = padString + string
}
return string
}
let originalString = "hello"
let paddedString = alignRight(originalString, totalLength: 10, pad: "-")
// paddedString is equal to "-----hello"
// originalString is still equal to "hello"
In-Out Parameters
變量參數,正如上面所述,僅能在函數體內被更改。如果你想要一個函數可以修改參數的值,並且想要在這些修改在函數調用結束後仍然存在,那麼就應該把這個參數定義為輸入輸出參數(In-Out Parameters)。
In-out parameters cannot have default values, and variadic parameters cannot be marked as inout. If you mark a parameter as inout, it cannot also be marked as var or let.
func swapTwoInts(inout a: Int, inout _ b: Int) {
let temporaryA = a
a = b
b = temporaryA
}
var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt)
print("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
// prints "someInt is now 107, and anotherInt is now 3"
Function Types
Every function has a specific function type
, made up of the parameter types and the return type of the function.
func addTwoInts(a: Int, _ b: Int) -> Int {
return a + b
}
func multiplyTwoInts(a: Int, _ b: Int) -> Int {
return a * b
}
這兩個函數的類型是(Int, Int) -> Int,可以解讀為“A function type that has two parameters, both of type Int, and that returns a value of type Int.”。
Using Function Types
You use function types just like any other types in Swift.
var mathFunction: (Int, Int) -> Int = addTwoInts
This can be read as:
“Define a variable called mathFunction, which has a type of ‘a function that takes two Int values, and returns an Int value.’ Set this new variable to refer to the function called addTwoInts.”
print("Result: \(mathFunction(2, 3))")
// prints "Result: 5"
As with any other type, you can leave it to Swift to infer the function type when you assign a function to a constant or variable:
let anotherMathFunction = addTwoInts
// anotherMathFunction is inferred to be of type (Int, Int) -> Int
Function Types as Parameter Types
可以用(Int, Int) -> Int這樣的函數類型作為另一個函數的參數類型。這樣你可以將函數的一部分實現留給函數的調用者來提供。
func printMathResult(mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int) {
print("Result: \(mathFunction(a, b))")
}
printMathResult(addTwoInts, 3, 5)
// prints "Result: 8"
這個例子定義了printMathResult(::_:) 函數,它有三個參數:第一個參數叫mathFunction,類型是(Int, Int) -> Int,你可以傳入任何這種類型的函數;第二個和第三個參數叫a 和b,它們的類型都是Int
Function Types as Return Types
You can use a function type as the return type of another function. You do this by writing a complete function type immediately after the return arrow (->) of the returning function.
func stepForward(input: Int) -> Int {
return input + 1
}
func stepBackward(input: Int) -> Int {
return input - 1
}
Here’s a function called chooseStepFunction(_:), whose return type is “a function of type (Int) -> Int”.
func chooseStepFunction(backwards: Bool) -> (Int) -> Int {
return backwards ? stepBackward : stepForward
}
var currentValue = 3
let moveNearerToZero = chooseStepFunction(currentValue > 0)
// moveNearerToZero now refers to the stepBackward() function
print("Counting to zero:")
// Counting to zero:
while currentValue != 0 {
print("\(currentValue)... ")
currentValue = moveNearerToZero(currentValue)
}
print("zero!")
// 3...
// 2...
// 1...
// zero!
Nested Functions
到目前為止所見到的所有函數都叫全局函數(global functions),它們定義在全局域中。你也可以把函數定義在別的函數體中,稱作嵌套函數(nested functions)。
嵌套函數是對外界不可見的,但是可以被它們的外圍函數(enclosing function)調用。
func chooseStepFunction(backwards: Bool) -> (Int) -> Int {
func stepForward(input: Int) -> Int { return input + 1 }
func stepBackward(input: Int) -> Int { return input - 1 }
return backwards ? stepBackward : stepForward
}
var currentValue = -4
let moveNearerToZero = chooseStepFunction(currentValue > 0)
// moveNearerToZero now refers to the nested stepForward() function
while currentValue != 0 {
print("\(currentValue)... ")
currentValue = moveNearerToZero(currentValue)
}
print("zero!")
// -4...
// -3...
// -2...
// -1...
// zero!
參考資料:
1. https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/index.html#//apple_ref/doc/uid/TP40014097-CH3-ID0
2. http://wiki.jikexueyuan.com/project/swift/
沒有留言:
張貼留言