Swift 簡介 / Swift 基礎
在本章中,您將學習如何使用 Swift[1] 的基本概念,包括變數、常量和陣列。本章涵蓋的另一個重要主題是如何在 Swift 中編寫函式和類。
與大多數其他語言一樣,Swift 使用變數來儲存值並透過唯一的名稱引用它們。這些變數的值可以是可變的或不可變的。建議在值的程式碼中不需要更改時使用常量。這也使您編寫的程式碼更安全。
在 Swift 中,變數使用關鍵字 var 宣告。建議僅在以後需要更改變數的值時才使用 var。
var greeting = "Good morning!"
如果不需要更改變數的值,則可以使用關鍵字 let 宣告它。
let answerToEverything = 42
型別標註可用於明確常量或變數可以儲存哪些型別的值。如果不存在初始值,則需要型別標註。如果提供了初始值,Swift 會推斷變數應該具有哪種型別。
var greeting: String
//Declaring a single variable
let alpha, beta, gamma: Double
//Declaring 3 variables in one line
如果應該更改變數的值,則它必須與原始值的型別相同。在本例中,greeting 的值更改為另一個 String "Good evening"。
var greeting = "Good morning!"
greeting = "Good evening!"
//greeting has now the value "Good evening!"
let pi = 3.1415
pi = 3.2
// Compile-time error: This value cannot be changed
Swift 是一種型別安全的語言,這意味著例如,無法將數字分配給儲存 String 的變數,也無法使用錯誤型別的引數呼叫函式。在編譯時,Swift 會執行型別檢查,只有在不存在型別不匹配的情況下才會完成編譯。
如果您在未指定型別的情況下宣告變數或常量,Swift 會使用型別推斷來找出適當的型別。如果您在宣告變數時提供浮點數,Swift 會推斷它為 Double 型別的值。
let absolutZero = -273.15
// absolutZero is inferred to be of type Double
整數是像 45 或 -37 這樣的整數。它們沒有小數部分,並且是有符號或無符號的。如果整數是有符號的,它可以是零、正數或負數。無符號整數只能是零或正數。Swift 提供 8、16、32 和 64 位形式的整數型別。雖然可以選擇特定大小,例如 UInt8 或 Int32,但在大多數情況下使用 Int 型別。它的大小與平臺的本機字長相同。在現代作業系統中,它的大小為 64 位。Uint 是一種無符號整數型別,其大小也與平臺的字長相同。
具有小數部分的浮點數可以表示比 Int 的可能值大得多或小得多的值。諸如 -0.0001 或 19.99 之類的數字可以儲存在 Double 或 Float 型別的變數中。Double 是一種 64 位浮點數,其精度至少為 15 位小數。Float 提供 6 位小數的精度。
在 Swift 中,布林值資料型別稱為 Bool,它可以具有常數值 true 或 false。
var switchedOn = true
// switchedOn is now true and of type Boolean
switchedOn = false
布林值非常適合用於控制流操作,例如 if 語句
if switchedOn{
print("The light is on!")
// Will be executed if switchedOn = true
}
else{
print("It's dark as a dungeon!")
}
可選變數有兩種可能的狀態:存在值或不存在值。要宣告具有可選資料型別的變數,請使用 ?。
var salary: Double?
// salary is set to nil automatically and contains no value
salary = 1923.12
// salary now has a value but is still of type Double?
salary = nil
// salary is set back to nil and contains no value
要確定值是否已設定,可以使用 if 語句以及 ==(等於)或 !=(不等於)運算子。
if salary == nil{
print("Salary for this employee has not been set yet!")
} else {
print("This employee's salary is \(salary!)")
}
在上面的示例中,您可以在可選名稱的末尾看到一個感嘆號。它用於解包可選的值以使用它。如果對不包含值的可選使用 !,將觸發執行時錯誤。
可選繫結檢查可選型別是否已設定,如果已設定,則將其值設定為一個新的臨時可用的變數或常量。
if let netSalary = salary{
print("This emplyee's net salary is \(netSalary*0.85)")
} else {
print("Salary for this employee has not been set yet!")
}
新的常量 netSalary 僅在 if 語句中可用,不需要解包。
集合型別
[edit | edit source]在 Swift 中,有三種主要的集合型別。
- 陣列用於儲存有序的值集合
- 集合用於儲存無序的唯一值集合
- 字典用於儲存無序的鍵值對
就像變數和常量一樣,所有三種集合型別都是型別安全的,這意味著無法插入錯誤型別的的值。這種型別安全性的積極方面是,您始終知道從集合中獲取的值的型別。
分配給變數的陣列、集合和字典是可變的,這意味著在建立後可以新增、更改或刪除值。如果需要不可變的集合型別,則必須將其分配給常量。
陣列
[edit | edit source]陣列提供相同型別元素的有序列表。有兩種方法可以宣告一個數組,Array<Element> 或 [Element]。Element 是應該儲存在陣列中的值的型別。陣列可以為空建立,也可以填充值建立。也可以使用預設值建立陣列。
var intArray = Array<Int>()
// creates an empty Integer Array
var preinitialized = Array(repeating: 1, count: 5)
print(preinitialized)
// prints "[1, 1, 1, 1, 1]"
陣列也可以使用陣列字面量初始化。這是一個用逗號分隔的值列表。
let fibonacci = [1,1,2,3,5,8,13]
// creates an immutable Integer Array
陣列的屬性和方法
[edit | edit source]intArray.append(9)
// Adds '9' to intArray
intArray += [1,2,3]
// emptyInt now contains 9, 1, 2 and 3
print(intArray.count)
// prints the number of elements in the array, 4
if(intArray.isEmpty){
print("I'm an empty Array! :( ")
} else {{
print("I'm storing \(intArray.count) elements!")
}
下標語法用於訪問陣列中的元素。索引從零開始,這意味著要訪問陣列的第一個元素,您必須在陣列的名稱中新增 [0]。
var firstValue = intArray[0]
// firstValue is now 9
集合
[edit | edit source]集合儲存相同型別的的值,並在專案的順序不重要時使用。集合還確保不出現重複的值。只有當值可雜湊時,才能將它們儲存在集合中。Swift 的基本型別,如 String、Int 和 Bool,預設情況下都是可雜湊的。
var devices = Set<String>()
// creates a new empty set
devices.insert("iPhone")
print(devices)
// prints ["iPhone"]
var webSuffixes: Set<String> = [".html", ".js", ".css"]
print(webSuffixes)
// prints [".js", ".html", ".css"]
print("There are \(webSuffixes.count) common suffixes in web development.")
// prints There are 3 common suffixes in web development.
if webSuffixes.contains(".py"){
print("Yeah, Python made it to the top 3 :)")
} else {
print("Python is not in the top 3 :( ")
}
// prints "Python is not in the top 3 :( "
for suffix in webSuffixes{
print ("\(suffix)")
}
// .css
// .js
// .html
集合提供了大量的集合運算。這些運算實現了數學集合論中最重要的規則。
- 交集
- 對稱差
- 並集
- 減法
以下程式碼片段展示了這些運算的工作原理。
let favSongs: Set = ["Enter Sandman", "Bohemian Rapsody", "Blitzkrieg Bop", "Painkiller"]
let songsFrom90s: Set = ["Raining Blood","Enter Sandman","Painkiller","Wonderwall"]
var playList = Set<String>()
playList = favSongs.union(songsFrom90s)
/* union combines the values of both sets, values which are in both sets will be displayed once.
["Blitzkrieg Bop", "Raining Blood", "Bohemian Rapsody", "Enter Sandman", "Painkiller", "Wonderwall"]*/
playList = favSongs.intersection(songsFrom90s)
/* intersect creates a new list which contains all values that exist in both Sets ["Enter Sandman", "Painkiller"] */
playList = favSongs.symmetricDifference(songsFrom90s)
/* symmetricDifference stores all values of both sets into a new set, except those which were in both sets.
["Blitzkrieg Bop", "Raining Blood", "Bohemian Rapsody", "Wonderwall"]*/
playList = favSongs.subtracting(songsFrom90s)
/*subtracting creates a new set which only includes values which are not in the second set. ["Blitzkrieg Bop", "Bohemian Rapsody"] */
字典
[edit | edit source]字典在無序集合中儲存鍵值對。鍵是值的唯一識別符號。與陣列類似,有兩種方法可以宣告字典。Dictionary<Key, Value> 或 [Key: Value]。此外,字典也可以使用字典字面量建立。
var offeredStudies = [String: String]()
// creates an empty [String: String] dictionary
offeredStudies["SWD"] = "Software-Design"
offeredStudies["ITM"] = "Internettechnik"
// adds two key-value pairs to the dictionary
offeredStudies["ITM"] = "Internettechnik und Mediendesign"
// changes the value of "ITM"
print(offeredStudies)
// prints ["SWD": "Software-Design", "ITM": "Internettechnik und Mediendesign"]
var locations: [String: String] = ["K": "Kapfenberg", "G": "Graz", "B": "Bad Gleichenberg"]
// creates a dictionary with a dictionary literal
print("FH Joanneum has \(locations.count) locations in Styria.")
// prints "FH Joanneum has 3 locations in Styria."
for (shortcut, location) in locations{
print("\(shortcut) is a shortcut for \(location)")
// G is a shortcut for Graz
// K is a shortcut for Kapfenberg
// B is a shortcut for Bad Gleichenberg
}
控制流
[edit | edit source]Swift 提供了許多方法來控制程式碼的執行方式。
For-In 迴圈
[edit | edit source]使用 For-In 迴圈是一種簡單的方法,可以遍歷陣列、集合或任何其他型別的序列或範圍。
let grades: [Int: String] = [1: "Sehr Gut", 2: "Gut", 3: "Befriedigend", 4: "Genuegend", 5: "Nicht genuegend"]for (grade, word) in grades.sorted(by: <){
print("\(grade) is a \"\(word)\"")
}
// 1 is a "Sehr Gut"
// 2 is a "Gut"
// 3 is a "Befriedigend"
// 4 is a "Genuegend"
// 5 is a "Nicht genuegend"
在典型的 For-In 迴圈中,計數器始終增加 1。如果您想要進行更小或更大的步長,則必須使用 stride。
let max = 100
for quarters in stride(from: 25, to: max, by: 25){
print(quarters)
}
// 25
// 50
// 75
While 迴圈
[edit | edit source]While 迴圈非常有用,如果您不知道需要多少次迭代。只要條件為真,while 迴圈就會執行語句。有兩種型別的 while 迴圈。
- while 在執行語句之前檢查條件是否為真。
- repeat-while 執行語句,並在最後檢查條件是否仍然為真。
var cardValues = [Int]()
for value in 1...10{
cardValues.append(value)
// creates an array with values 1 to 10 - simulates a card deck
}
var bankCount = 0
while bankCount < 21 {
var randomIndex = Int(arc4random_uniform(UInt32(cardValues.count)))
// creates a random number - simulates picking a random card
bankCount += cardValues[randomIndex]
print(bankCount)
if(bankCount > 21){
print("The bank loses!")
}
else if(bankCount == 21){
print("The bank wins!")
}
}
如果
[edit | edit source]if 語句是決定應執行哪些語句的最簡單方法,基於某些條件。如果只有少數可能的條件,則使用它。if 語句可以獨立存在,但最好始終提供 else 語句,因為它使程式碼更易讀和理解。=== Switch ===
var switchedOn = true
if(switchedOn == true){
print("All lights are on")
} else {
print("Can someone please turn on the light?")
}
還可以為不止一個條件提供不同的程式碼路徑
var score = 88;
if(score > 90 && score <= 100){
print("Perfect!")
} else if(score > 80 && score <= 90){
print("Good Job!")
} else if(score > 70 && score <= 80){
print("Not Bad!")
} else if(score > 60 && score <= 70){
print("Puh, that was close!")
} else{
print("Good luck next time")
}
如您所見,隨著條件數量的增加,會產生大量重複的程式碼。可以使用 switch 語句來減少重複程式碼的數量。
開關
[edit | edit source]switch 語句通常有幾種可能的條件情況。所有 switch 語句都必須是窮舉的,這意味著條件的每個可能值都必須有一個情況。因此,應該提供一個預設語句,如果這些情況都不匹配,則會執行該語句。
var grade = "A"
switch grade{
case "A":
print("Excellent")
case "B":
print("Above average")
case "C":
print("Satisfactory")
case "D":
print("Below Average")
case "F":
print("Failure")
default:
print("Test not attempted")
}
函式
[edit | edit source]函式是程式碼的重要組成部分。它們具有標識名稱 - 最好使用描述函式功能的名稱 - 在呼叫函式時使用該名稱。它們可以有零到多個引數。這些輸入值在呼叫函式時傳遞。
定義和呼叫函式
[edit | edit source]在下面的程式碼片段中,您可以看到函式的定義以 fund 開頭,後面是名稱和可選的引數列表。-> 運算子指定此函式的返回型別。沒有箭頭定義的函式沒有返回值。
func combineStrings(begin: String, end: String) -> String{
let combinedString = begin + end
return combinedString
}
print(combineStrings(begin: "Let's get ", end: "swifty!"))
// prints "Let's get swifty!"
引數和返回值
[edit | edit source]函式可以有零到多個引數,也可以有零到多個返回值。在下面的示例中,您可以看到一個函式,它以兩個整數值作為引數,並返回兩個整數值。第二個函式沒有引數,也沒有返回值。
func sumAndDifference(value1: Int, value2: Int) -> (sum: Int, difference: Int){
let sum = value1 + value2
let difference = value1 - value2
return (sum, difference)
}
func printTimestamp(){
let date = Date() //gets the current date
let calendar = Calendar.current
let hour = calendar.component(.hour, from: date)
let minutes = calendar.component(.minute, from: date)
print(String(hour) + ":" + String(minutes))
}
printTimestamp()
// prints hours and minutes whenever it is called
print(sumAndDifference(value1: 10, value2: 5))
// prints "(sum: 15, difference: 5)"
引數標籤和引數名稱
[edit | edit source]在 Swift 中,引數有一個引數標籤,在呼叫函式時使用它,還有一個引數名稱,在實現中使用它。
func getsFined(allowed speed: Double, measured value: Double) -> String {
if(speed < value){
return "Driver was too fast - that's gonna be expensive"
}
else{
return "Good boy"
}
}
print(getsFined(allowed: 100, measured: 120))
// prints "Driver was too fast - that's gonna be expensive"
也可以編寫沒有引數標籤的函式。
func add2Numbers(_ number1: Int, _ number2: Int) ->Int{
return number1 + number2
}
print(add2Numbers(4,8))
// 12
可變引數
[edit | edit source]這些引數接受相同型別的可變數量的引數。當您不知道要傳遞給函式的引數的確切數量,或者所需引數的數量從一個函式呼叫到另一個函式呼叫而變化時,它特別有用。
func calcCart(_ prices: Double...) -> String {
var sum: Double = 0
for price in prices{
sum += price
}
return String(sum)
}
print("The items in your cart cost " + calcCart(10.99, 9.99, 5.69))
// prints "The items in your cart cost 26.67"
函式型別
[edit | edit source]函式的型別包括引數型別和它的返回型別。讓我們看看上面程式碼片段中其中一個函式的函式型別。
func getsFined(allowed speed: Double, measured value: Double) -> String
此函式由兩個型別為 Double 的引數和一個型別為 String 的返回值組成。因此,函式型別為 (Double, Double) -> String
函式也可以有函式型別作為返回值。
func calcTaxFood(_ prices: Double...) -> String {
var sum: Double = 0
for price in prices{
sum += price*0.1
}
return String(sum)
}
func calcTaxNonFood(_ prices: Double...) -> String {
var sum: Double = 0
for price in prices{
sum += price*0.2
}
return String(sum)
}
func chooseTaxCalculator(isFood: Bool) ->(Double...) -> String {
return isFood ? calcTaxFood : calcTaxNonFood
// if isFood is true, calcTaxFood will be returned
// it it is false, calcTaxNonFood will be returned
}
let taxFood = chooseTaxCalculator(isFood: true)(19.99, 12.99, 6.79)
let taxNonFood = chooseTaxCalculator(isFood: false)(9.99, 1.99, 14.99)
print("You paid " + taxFood + "Euro taxes for your food and " + taxNonFood + "Euro for the rest.")
巢狀函式
[edit | edit source]在另一個函式中定義的函式稱為巢狀函式。它們在函式外部不可見。但是,如果封閉函式返回它們,則可以在函式外部使用它們。
func itemCounter(incoming: Bool) -> (Int) -> Int {
func increaseCount(count: Int) -> Int{
print("\(count) items were added to our current stock")
return itemsOnStock + count
}
func decreaseCount(count: Int) -> Int{
print("\(count) items were shipped to customers")
return itemsOnStock - count
}
return incoming ? increaseCount : decreaseCount
}
var itemsOnStock = 8
let itemsIncoming = itemCounter(incoming: true)
let itemsOutgoing = itemCounter(incoming: false)
print("There are \(itemsOnStock) items in the warehouse")
// There are 8 items in the warehouse
itemsOnStock = itemsIncoming(10)
// 10 items were added to our current stock
itemsOnStock = itemsOutgoing(7)
// 7 items were shipped to customers
print("There are \(itemsOnStock) items in the warehouse")
// There are 11 items in the warehouse
類和結構
[edit | edit source]作為面向物件的語言,Swift 也提供了類,它是物件或例項的構建計劃,以及結構,這是一種類似的結構。介面用於使類或結構可供其他程式碼部分使用,它們會自動提供。
類和結構共享許多功能,例如
- 屬性用於儲存值
- 方法提供功能
- 兩者都可以擴充套件
- 初始化器用於設定其初始狀態
但是,有些功能只有類提供
- 繼承
- 在執行時檢查和解釋類的型別
- 類可以使用解構函式釋放資源
類還是結構?
[edit | edit source]在決定類或結構哪種更適合您的需求之前,需要考慮這兩種結構的一些特徵。其中一個最重要的區別是,類總是按引用傳遞,而結構按值傳遞。
Apple 建議[2] 在以下情況下使用結構
- 結構的主要目的是封裝一些簡單的數值。
- 合理預期這些值將被複制,而不是被引用。
- 結構中的所有屬性都是值型別。
- 結構不需要從其他現有型別繼承屬性或行為。
在下面的程式碼片段中,您可以看到兩個結構,SoftTyre 和 HardTyre,它們儲存描述輪胎特徵的值。如您所見,只儲存了簡單的值,例如整數和布林值。Racecar 類也包含一些簡單的數值,例如重量或車隊名稱,但也包含 SlickTyre 結構的例項。
struct DryTyre{
var forWetCondition = false
var grip = 3
var durability = 3
}
struct WetTyre{
var forWetCondition = true
var grip = 4
var durability = 2
}
class Racecar{
let teamName = "Red Bull Racing"
var tyre = DryTyre()
var weightEmpty = 650
var weightWithDriver = 728
}
訪問屬性
[edit | edit source]可以使用點語法訪問類和結構的屬性。
var car = Racecar()
// create an instance
print("\(car.weightEmpty)")
// prints "650"
car.weightWithDriver = 732
// assign a new value using dot syntax
print("This tyre suits for wet conditions: \(car.tyre.forWetCondition)\nand has a durability value of: \(car.tyre.durability)")
// This tyre suits for wet conditions: false
// and has a durability value of: 3
結構型別的逐成員初始化
[edit | edit source]可以使用自動生成的逐成員初始化器來初始化新結構例項的屬性。
let superSoft = SoftTyre(forWetCondition: false, grip: 4, durability: 2)
// create and initialize a new instance of the SoftTyre struct
car.tyre = superSoft
print("This tyre has a durability value of: \(car.tyre.durability)")
// This tyre has a durability value of: 2
值型別與引用型別
[edit | edit source]結構、列舉和 Swift 中的所有基本型別,例如整數、字串和陣列,都是值型別,這意味著當它們被傳遞給函式時,值會被複制。對函式內部複製的整數值進行的更改不會影響外部的原始值。
let ultraSoft = SoftTyre(forWetCondition: false, grip: 5, durability: 1)
var tyre = ultraSoft
tyre.durability = 4
print("Durability of tyre is now \(tyre.durability)")
// Durability of tyre is now 4
print("Durability of ultraSoft ist still \(ultraSoft.durability)")
// Durability of ultraSoft ist still 1
類是引用型別,這意味著當它們被傳遞給函式時,不會被複制。相反,會使用對已存在例項的引用。在下面的程式碼片段中,Racecar 的例項被分配給名為 rb13 的常量。在分配屬性 raceWins 和 weightEmpty 後,rb13 被分配給一個新的常量 rb14。由於 Racecar 類的例項是按引用傳遞的,因此 rb14 中的更改會自動影響 rb13 中的屬性。
let rb13 = Racecar()
rb13.raceWins = 39
rb13.weightEmpty = 680
let rb14 = rb13
rb14.raceWins = 42
rb14.weightEmpty = 700
print("rb13 now also has \(rb13.weightEmpty) kg and \(rb13.raceWins) wins")
// rb13 now also has 700 kg and 42 wins
引用
[edit | edit source]- ↑ Apple Inc. | 2017 | Swift 程式語言 | [線上][訪問:2017 年 9 月 18 日] | https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/index.html#//apple_ref/doc/uid/TP40014097-CH3-ID0
- ↑ Apple Inc. | 2017 | Swift - 類和結構 | [線上][訪問:2017 年 9 月 18 日] | https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/ClassesAndStructures.html#//apple_ref/doc/uid/TP40014097-CH13-ID82