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