Swift学习笔记(一)基础语法_swift 学习-程序员宅基地

技术标签: 学习  笔记  swift  


前言

浅学一下Swift,这篇笔记做个记录


开发工具

依然是Xcode,关于Xcode就不多介绍了。

在这里插入图片描述

变量与常量

let关键字和var关键字分别用来表示常量和变量,无论是let还是var,作用都是为某个具体量值取了一个名字,这种方式叫做量值的声明。在量值的有效作用域内,开发者可以使用这些名称来获取具体的量值,编程中有两个基本的概念:量值和表达式。
可以理解量值是结果。3是一个整数型量值,字符串hello是一个字符串型量值。
表达式可以理解为一个计算过程,结果是一个量值。1+2是一个表达式,结果为量值3.
hello+world也是一个表达式,结果为量值hello world。
大多数表达式是由量值和运算符组成的。

变量和常量的定义和使用

//引入UIKit框架
import UIKit
//定义一个变量,赋值为字符串“hello,playground”
var greeting = "Hello, playground"
//定义一个变量,赋值为字符串“hello,playground”
var greeting = "Hello, playground"



//这句代码和下面这句代码等效

//声明字符串变量
var str: String
//对字符串变量str进行赋值
str = "hello,playground"




//量值的打印
print(str)
//在使用常量或者变量时,开发者可以直接通过名称来调用对应的量值,
str = "newValue"

//在str后追加hello
str = str + "hello"

Swift也支持在同一行语句中声明多个常量或者变量,但要遵守明确类型的原则

var a = 1, b = 2, c = "string"
var a2 : Int = 1, b2 : Float = 2.9, c2 : String = "string"

如果在同一行代码中声明多个变量并且都没有提供初始值,可以通过指定最后一个变量的类型怼整体进行类型指定

var one, two, three : Int

上述代码中声明的var one, two, three都是Int类型变量

(1) Swift 语言是一种十分快速简洁的语言,其允许开収者省略分号,自动以换行杢分隔语 句,同时支持在一行中编写多句代码,此时需要使用分号对语句分隔,例如:
var str:String;str = “hello,playground”;print(str)
(2) 对 Swift 语言的类型推断是 Xcode 编译器一个十分优秀的特性,在实际开収中,开収者 应该尽量使用这种特性。
(3) 如果需要修改变量的值,直接对变量再赋值即可。需要注意的是,所赋值的类型必须 和变量的类型保持一致。

变量和常量的命名规范

在Swift语言中,常量和变量的命名规则十分宽泛,可以包括Unicode字符和数字,需要注意的 是,不可使用预留关键字来作为常量或者变量的名称,例如let、var这类关键字不可作为量值名来 声明。另外,常量和变量的命名不可以数字开头,空格、数学符号、制表符、箭头等符号也不可用 在命名中。在这里插入图片描述

也可以使用穿插数字进行命名,注意数字不能作为开头:
//含有数字的命名 var pen2 = “钢笔”
也可以使用下画线进行命名: //使用下画线进行命名
var swift = “swift”

虽然Swift支持的命名方式十分广泛,但在实际开发中,良好的命名风格可以大大提高编码效 率与代码的可读性。Swift语言官方文档采用驼峰命名的方式。所谓驼峰命名,是指以单词进行名 称的拼接,名称的首字母一般为小写,之后每个单词的首字母大写,其他字母均小写,示例如 下:
//驼峰命名
var userName = “珲少”

(1) Unicode(统一码、万国码、单一码)是计算机科学领域的一项业界标准,包括字符 集、编码斱案等。Unicode 是为了解决传统的字符编码斱案的局限而产生的,它为每种语 言中的每个字符设定了统一幵且唯一的二迚制编码,以满足跨语言、跨平台迚行文本转 换、处理的要求。Unicode 于 1990 年开始研収,1994 年正式公布。
(2) Swift 中的命名也有一些约定俗成的觃则,例如量值属性首字母会小写,类名、枚丽名、 结极体名首字母会大写。
(3) 如果在命名中真的需要使用预留的关键字迚行命名,可使用符号迚行包装,但是除非 万不得已,开収中尽量不要使用这种斱式命名,包装示例如下: //用预留关键字迚行命名 var var` = 2

注释

单行注释,多行注释都和OC的注释相同。
但是Swift可以进行注释嵌套。

//单行注释//注释中的注释 /*
多行注释
/*
*/
注释 注释 */

初识基本数据类型

Swift语言中的整型数据分为有符号整型数据与无符号整型数据。所谓有符号与无符号,通俗 的理解即为分正负号与不分正负号。
对于无符号整型,Swift中提供了5种类型4种存储空间的数据类型,4种存储空间分别占用内存 8位、16位、32位和64位。使用Xcode开发工具创建一个新的Playground,命名为BasicDataType,编 写如下演示代码:
对于无符号整型,Swift中提供了5种类型4种存储空间的数据类型,4种存储空间分别占用内存 8位、16位、32位和64位。使用Xcode开发工具创建一个新的Playground,命名为BasicDataType,编 写如下演示代码:

//8 位无符号整型数的最大值 255 
var a1 = UInt8.max
//16 位无符号整型数的最大值 65535 
var a2 = UInt16.max
//32 位无符号整型数的最大值 4294967295
var a3 = UInt32.max
//64 位无符号整型数的最大值 18446744073709551615 
var a4 = UInt64.max

上面的代码中创建了4个变量a1、a2、a3、a4。在Swift语言中,整型数据类型实际上是采用结 构体的方式实现的,其中max属性可以获取当前类型的最大值。读者可能会有疑问,在实际开发 中,到底应该选择哪一种类型来表达无符号整型呢?上面有提到,Swift语言中的无符号整型实际 上有5种,还有1种为UInt类型,这种类型编译器会自动适配,在64位的机器上为UInt64,在32位 的机器上为UInt32,示例代码如下:

var a6 = MemoryLayout<UInt>.size

MemoryLayout是Swift标准库中定义的一个枚举,顾名思义其实用于获取内存相关信息, MemoryLayout则是一种泛型的用法,调用其size属性可以获取某种数据类型所占内存空间的 字节数。
有符号整型数据与无符号整型数据十分类似,只是其首位二进制位为符号位,不纳入数值计 算,示例代码如下:

var maxInt8 = Int8.max //127
var mimInt8 = Int8.min //-128
var maxInt16 = Int16.max //32767
var minInt16 = Int16.min //-32768
var maxInt32 = Int32.max //2147483647
var minInt32 = Int32.min //-2147483648
var maxInt64 = Int64.max //9223372036854775807 var minInt64 = Int64.min //-9223372036854775808 var intSize = sizeof(Int) //8位

与max属性对应,min属性用于获取整型数据的最小值。

浮点型数据

var b = MemoryLayout<Float>.size 
var b1 = MemoryLayout<Float32>.size 
var b2 = MemoryLayout<Float64>.size 
var b3 = MemoryLayout<Float80>.size 
var c = MemoryLayout<Double>.size
//4字节 
//4字节 
//8字节 
//16字节 
//8字节

Swift语言支持使用科学计数法来表示数字,在十进制中,使用e来表示10的n次方,在十六进 制中,使用p来表示2的n次方,示例代码如下:

var sum = 1.25e3 //1.25*(10^3) = 1250 var sun2 = 0x1p3 //1*(2^3) = 8

Swift语言中还有一个十分有意思的特性,无论是整型数据还是浮点型数据,都可以在数字前加 任意个0来进行位数填充,也可以在数字中加入下画线进行分隔,进而增加可读性,这些操作并不会 影响原始数值,却提高了对开发者编程的友好性,使代码的结构更加清爽,示例如下:

var num1 = 001.23 //1.23
var num2 = 1_000  //1000
var num3 = 1_000.1_ 001 //1000.1001

布尔型数据

布尔类型很多时候也叫作逻辑类型,熟悉Objective-C编程语言的读者可能会了解,在 Objective-C语言中,Bool类型其实并非严格意义上的逻辑布尔类型,Objective-C中可以使用零与非 零来表达逻辑假与逻辑真。而在Swift语言中则不同,Swift语言的Bool类型十分严格,只有true和false 两种值,分别表示真和假。同样,在Swift语言的条件语句以及需要进行逻辑判断的语句中,所使 用的条件表达式的值也必须为Bool类型。

两种特殊的基本数据类型

Swift语言还支持两种特殊的基本数据类型,分别是元组类型与可选值类型。元组在实际开发 中十分常用,开发者使用元组可以创建出任意数据类型组合的自定义数据类型;而可选值类型是 Swift语言的一大特点,通过可选值类型,Swift语言对数值为空进行了严格的把控。

元组

元组是Swift语言中重要的数据类型之一,元组允许一些并不相关的类型自由组合成为新的集 合类型。Objective-C语言并不支持元组这样的数据类型,这在很多时候会给开发者带来麻烦。类比 生活中的一种情景,元组类型类似于日常生活中的套餐,现在各种服务业都推出了许多有特色的套 餐供顾客选择,方便为顾客提供一站式服务。元组提供的就是这样一种编程结构,试想一下,编程 中遇到这样一种情形:一个商品有名字和价格,使用元组可以很好地对这种商品类型进行模拟,示 例如下:

//创建钢笔元组类型,其中有两种类型,字符串类型的名称和整数类型的价钱
var pen : (name : String, pricr : Int) = ("钢笔", 2)

上边的代码在创建元组时同时指定了其中的参数的名称,即名称参数为name,价格参数price,开发者可以使用这些参数名称来获取元组中各个参数的值

var name = pen.name
var price = pen.price

创建元组时,可以不指定参数名称,元组会自动为每个参数分配下标,下标值将从0开始依次递增

var car : (String, Int) = ("奔驰", 20000000)
var carName = car.0
var carPrice = car.1

元组实例被创建后,开发者也可以通过指定的变量或者常量来分解它,

//不指定参数名称的元组
var car : (String, Int) = ("奔驰", 2000000)

//进行元组的分解
var (theName, thePrice) = car
//此时theName变量被赋值为“奔驰“, thePrice被赋值为2000000
print(theName, thePrice)

上面的代码将元组实例car的各个组成元素分解到具体变量,有一点读者需要注意,分解后的变量必须与元组中的元素一一对应(个数相等),否则编译器会出错。
print()函数为打印输出函数,print()函数可以接收多个参数,将其以,分隔即可
有些时候,开发者可 能并不需要获取某个元组实例中所有元素的值,这种情况下,开发者也可以将某些不需要获取的 元素使用匿名的方式来接收,示例如下:

//不指定参数名称的元组
var car : (String, Int) = ("奔驰", 2000000)
//进行元组的分解,将Int型参数进行匿名
var (theName, _) = car
//此时theName被赋值为“奔驰”
print(theName)

在Swift语言中,常常使用符号“”来表示匿名的概念,因此“”也被称为匿名标识符。上 面的代码实际上只分解出了元组car中的第一个元素(String类型)。
元组虽然使用起杢十分斱便,但是其只适用于简单数据的组合,对于结极复杂的数据,要 采用结极体或者类杢实现。

可选值类型

可选值类型(Optional类型)是Swift语言特有的一种类型。首先,Swift语言是一种十分强调类 型安全的语言,开发者在使用到某个变量时,编译器会尽最大可能保证此变量的类型和值的明确性, 保证减少编程中的不可控因素。然而在实际编程中,任何类型的变量都会遇到值为空的情况,在 Objective-C语言中并没有机制来专门监控和管理为空值的变量,程序的运行安全性全部靠开发者手 动控制。Swift语言提供了一种包装的方式来对普通类型进行Optional包装,实现对空值情况的监控。
在Swift语言中,如果使用了一个没有赋值的变量,程序会直接报错并停止运行。读者可能会 想,如果一个变量在声明的时候没有赋初值,在后面的程序运行中就有可能被赋值,那么对于这种 “先声明后赋值”的应用场景,我们应该怎么做呢?在Objective-C中,这个问题很好解决,只需要 使用的时候判断一下这个变量是否为nil即可。在Swift中是否也可以这样做呢?使用如下代码来进 行试验:
在Swift语言中,如果使用了一个没有赋值的变量,程序会直接报错并停止运行。读者可能会 想,如果一个变量在声明的时候没有赋初值,在后面的程序运行中就有可能被赋值,那么对于这种 “先声明后赋值”的应用场景,我们应该怎么做呢?在Objective-C中,这个问题很好解决,只需要 使用的时候判断一下这个变量是否为nil即可。在Swift中是否也可以这样做呢?使用如下代码来进 行试验:

var obj:String 
if obj==nil {
    
}

在这里插入图片描述
编写上面的代码后,可以看到Xcode工具依然抛出了一个错误提示,其实在Swift语言中,未做 初始化的普通类型是不允许使用的,哪怕是用来进行判空处理也不被允许,当然也就不可以与nil 进行比较运算,这种机制极大地减小了代码的不可控性。因此,开发者在使用前必须保证变量被初 始化,代码如下:


var obj0 : String
obj0 = "HS"
print(obj0)

但是上面的做法在实际开发中并不常用,如果一个变量在逻辑上可能为nil,则开发者需要将 其包装为Optional类型,改写上面的代码如下:

var obj : String?
if obj == nil {
    
    
}

此时代码就可以正常运行了。分析上面的代码,在声明obj变量的时候,这里将其声明成了String? 类型,在普通类型后面添加符号“?”,即可将普通类型包装为Optional类型
Optional类型不会独立存在,其总是附着于某个具体的数据类型之上,具体的数据类型可以是 基本数据类型,可以是结构体,也可以是类等。Optional类型只有两种值,读者可以将其理解为:

  • 如果其附着类型对应的量值有具体的值,则其为具体值的包装。
  • 如果其附着类型对应的量值没有具体的值,则其为nil。
  • Optional 类型中的 nil 读者也可以理解为一种值,其表示空

Optional类型是对普通类型的一种包装,因此在使用的时候需要对其进行拆包操作,拆包将使 用到Swift中的操作符“!”。“?”与“!”这两个操作符是很多Swift语言初学者的噩梦,如果读者 理解了Optional类型,那么对这两个操作符的理解和使用将容易许多。首先需要注意,“?”符号可 以出现在类型后面,也可以出现在实例后面,如果出现在类型后面,其代表的是此类型对应的 Optional类型,如果出现在实例后面,则代表的是可选链的调用,后面章节会详细介绍。“!”符 号同样可以出现在类型后面与实例后面,它出现在类型后面代表的是一种隐式解析的语法结构,后 面章节会介绍;出现在实例后面代表的是对Optional类型实例的拆包操作。示例如下:

//声明obj为String?类型
var obj : String? = "HS"
//进行拆包操作
obj!

读者需要注意,在使用“!”进行Optional值的拆包操作时,必须保证要拆包的值不为nil,否 则程序运行会出错。可以在拆包前使用if语句进行安全判断,示例如下:

var obj : String? = "HS"
if obj != nil {
    
    obj!
}

如果obj有值,则if-let结构将创建一个临时常量tmp来接收obj拆包 后的值,并且执行if为真时所对应的代码块,在执行的代码块中,开发者可以直接使用拆包后的obj 值tmp。如果obj为nil,则会进入if为假的代码块中,开发者可以在else代码块中将obj重新赋值使用。 这种if-let结构实际上完成了判断、拆包、绑定拆包后的值到临时常量3个过程。
if-let结构中也可以同时进行多个Optional类型值的绑定,之间用逗号隔开,示例如下:

//if-let多Optional值绑定
var obj1 : Int? = 1
var obj2 : Int? = 2
if let tmp1 = obj1, let tmp2 = obj2 {
    
    print(tmp1, tmp2)
}

在同时进行多个Optional类型值的绑定时,只有所有Optional值都不为nil,绑定才会成功,代 码执行才会进入if为真的代码块中。

//if-let多Optional值绑定
var obj1 : Int? = 1
var obj2 : Int? = 2
if let tmp1 = obj1, let tmp2 = obj2, tmp1 < tmp2 {
    
    print(tmp1, tmp2)
}

上面的代码在obj1不为nil、obj2不为nil并且obj1所对应的拆包值小于obj2对应的拆包值的时候 才会进入if为真的代码块中,即打印绑定的tmp1与tmp2的值。
对于一个可选值类型的变量,每次使用时我们都需要为其进行拆包操作,这 相对会有些麻烦,其实Swift中还有一种语法:隐式解析。隐式解析适用于这样的场景:当我们 明确某个变量初始时为nil,并且在之后使用之前一定会被赋值时,我们可以将其声明为隐式解 析的可选值,再对这个变量进行使用,就不需要进行拆包操作了,例如下面的代码会产生运行 错误:在这里插入图片描述
会编译错误,因为obj4没有进行拆包

//声明obj4为隐式解析的变量
var obj4 : Int!
obj4 = 3
//使用时,无须再进行拆包操作,Swift会自动帮我们拆包
print(obj4 + 1)

为类型取别名

在C、C++、Objective-C这些语言中都提供了typedef这样的关键字来为某个类型取一个别名,
Swift语言中使用typealias关键字来实现相同的效果,示例如下:


//为Int类型取一个别名Price
typealias Price = Int
//使用Price代替Int, 效果完全一样
var penPrice : Price = 100

上面的代码为Int类型取了别名Price,在后面的使用中,Price类型和Int类型一模一样。在实际 开发中,灵活使用typealias为类型取别名可以优化代码的可读性。

模拟面试

(1)符号“?”和“!”是Swift工程中非常常见的两个符号,请简述你对它们的理解。 回答要点提示: 1首先从类型和实例两个方面理解,“?”出现在类型后表示Optional类型,出现在实例后表
示可选链调用。“!”出现在类型后表示默认隐式解析,出现在实例后表示强制拆包。 2这两个符号都与Swift中的Optional类型相关,Optional类型是Swift语言强调安全性的一种方
式,某个变量可不可以为空应该是逻辑上决定的,而不是不可预知、不可控的。 3if-let结构与Optional类型值结合使用可以编写出优雅安全的逻辑代码。
核心理解内容:
对Swift中的Optional类型做深入的理解。 (2)十进制、二进制、八进制、十六进制各有什么优势,在哪些场景下使用。 回答要点提示: 1十进制的优势不必多言,日常生活中几乎所有的数学计算使用的都是十进制,钱币的单位、
班级的座次、队伍的排序等都是以十进制表示的。 2二进制是计算机最方便理解的进制方式,高低电平状态非常容易表示二进制的0和1,同时
也是计算机运行最稳定的存储数据进制方式。 3八进制和十六进制实际上是二进制的聚合方式,在八进制中,每位数字可以表示二进制中
的3位,在十六进制中,每位数字可以表示二进制的4位,大大缩短了二进制数的长度,并且便于阅 读。常常使用十六进制来表示颜色数据。
核心理解内容:
进制的原理以及转换方法。
(3)Swift语言中是否只有var和let两种数据类型?
回答要点提示: 1这个命题大错特错,在Swift中,var和let并不是数据类型,只是两种用来声明变量的方
式。 2Swift是一种强数据类型,和C、C++、Objective-C、Java等语言一样,变量在声明时其数据
示例解析:
类型就已经确定,有时我们没有显式指定,是由于Xcode有自动类型推断功能。 3Swift中的数据类型有基本数据类型和引用数据类型,基本数据类型中又包含整型、浮点型、
布尔型、元组等。
核心理解内容:
理解数据类型的意义,理解变量和数据类型之间的关系,明白Xcode的自动类型推断功能。

字符、字符串与集合类型

在程序开发中,字符串的使用必不可少,其是编程中一种十分重要的数据类型,其实,字符 串也是一组字符的集合。有些语言是没有独立的字符串类型的,例如C语言,其往往采用字符数组 来作为字符串类型,Objective-C语言中封装了面向对象的字符串类型NSString,并向其中封装了大 量的相关方法。而Swift是一种弱化指针的语言,它提供了String类型和Character类型来描述字符串 与字符。

字符串类型

字符串类型顾名思义为一串字符的组合,其在开发中应用甚广,商品的名称、学生的班级、播放音乐的歌词等场景逻辑都需要通过字符串来处理。

var str = "hello, world"

var str = ""

字符串变量的值为空字符串与字符串变量的值为nil是两个完 全不同的概念,如果一个Optional类型变量没有赋值,则其为nil,如果赋值为空字符串,则其并不 是nil。
在Swift语言中,String类型实际上是一个结构体,其实前面章节中学习的整型、浮点型和布尔 型也是由结构体实现的。Swift语言中的结构体十分强大,其可以像类一样进行属性和方法的定义,


var str : String = "Hello, playground"
print(str)
str = ""
print(str)

str = String()
print(str)

str = String("hello")
print(str)

str = String(666)
print(str)

str = String(6.66)
print(str)

str = String("a")
print(str)

str = String(false)
print(str)

str = String(describing: (1, 2.0, true))
print(str)

str = String(describing: [1, 2, 3])
print(str)

str = String(format: "我是%@", "会少")
print(str)

在这里插入图片描述
Sring类型提供了很多重载的构造方法,开发者可以传入不同类型的参数来构造需要的字符串。实际上,Swift语言中的String类型提供的构造方式十分宽泛,甚至可以将其他类型通过构造
方法转换为字符串,示例如下:

var str : String = "Hello, playground"
print(str)

str = String(describing: Int.self)
print(str)

var a = Int(1.5)
print(a)
var b = Float(a)
print(b)

在这里插入图片描述

字符串的组合

Swift中的String类型对“+”运算符进行了重载实现,即开发者可以直接使用“+”符号将多个
字符串组合拼接为新的字符串,


var c1 = "Hello"

var c2 = "world"

var c3 = c1 + " " + c2
print(c3)

在这里插入图片描述
通过加法运算符,开发者可以十分方便地进行字符串变量的组合拼接,有时开发者需要在某 个字符串中间插入另一个字符串,除了可以使用格式化的构造方法外,Swift中还提供了一种十分 方便的字符串插值方法

使用()进行字符串插值

var d = "Hello\(123)"
print(d)
var d2 = "Hello\(d)"
print(d2)
var d3 = "Hello\(1 + 2)"
print(d3)

在这里插入图片描述
“()”结构可以将其他数据类型转换为字符串类型并且插入字符串数据的相应位置,也可以 进行简单的运算逻辑后将结果插入原字符串中,这种方法可以十分方便地进行字符串的格式化,在 开发中应用广泛。

字符类型

字符类型用来表示单个字符,如数字字符、英文字符、符号字符和中文字符等都可以使用字
符类型来表示,也可以通过遍历字符串的方法将字符串中的字符分解出来。

类似于C语言中的Char,Swift语言中使用Character来描述字符类型,Character类型和String类 型都占16字节的内存空间。在Swift中可以使用MemoryLayout枚举来获取某个类型所占用的内存空间,其单位为字节,示例如下:

print(MemoryLayout<String>.size)

在这里插入图片描述
Character用来描述一个字符,我们将一组字符组合成为一个数组,用于构造字符串,示例如
下:


var e : Character = "a"
var e2 : [Character] = ["H", "E", "L", "L", "O"]
var e3 = String(e2)
print(e, e2, e3)

在这里插入图片描述
使用for-in遍历可以将字符串中的字符拆解出来,这种方法有时十分好用,for-in遍历是Swift 语言中一种重要的代码流程结构。String类型默认实现了迭代器相关协议,直接对其进行遍历可以 取出字符串中的每一个字符元素,示例代码如下:

let name = "China"
for character in name {
    
    print(character)
}

在这里插入图片描述
for-in 结极是一种重要的循环结极,上面的示例代码中,in 关键字后面需要为一种可迭代的 类型,in 关键字前面是每次循环从迭代器中取出的元素,其类型会由 Xcode 编译器自动推断出

转义字符

Swift语言和C语言类似,除了一些常规的可见字符外,还提供了一些有特殊用途的转义字符,
可通过特殊的符号组合来表示特定的意义。示例如下:

  • \0:用杢表示空白符。
  • \:用来表示反斜杠
  • \t:用杢表示制表符。
  • \n:用杢表示换行符。
  • \r:用杢表示回车符。
  • ':用杢表示单引号
  • ":用杢表示双引号。
  • \u{}:用Unicode码杢创建字符。
    其中,\u{}用来通过Unicode码来创建字符,将Unicode码填入大括号中即可,示例如下: //使用 Unicode 码来创建字符,Unicode 为 21 代表的字符为!
    “\u{21}”

字符串类型中的常用方法

Swift语言的String类型中封装了许多实用的属性和方法,例如字符串的检查,字符的追加、插 入、删除操作,字符数的统计等。熟练使用这些属性与方法能够使得开发者在编程中处理数据时游 刃有余。
前面介绍过,字符串变量的值为空字符串与字符串变量的值为空是两个不同的概念,String类 型的实例通过使用isEmpty方法来判断字符串的值是否为空字符串

var obj1 = ""
if obj1.isEmpty {
    
    print("字符串为空字符串")
}

还有一种方式也可以用来判断一个字符串变量是否为空字符串,即当字符串变量中的字符数 为0时,也可以认定此字符串为空字符串,即通过字符串的count属性判断其中的字符个数是否为 0

var obj1 = ""
if obj1.count == 0 {
    
    print("字符串为空字符串")
}

String类型的实例除了可以使用“+”直接拼接外,还可以使用比较运算符

var com1 = "30a"
var com2 = "31a"
if com1 == com2 {
    
    print("com1 = com2")
}
if com1 < com2 {
    
    print("com1 < com2")
}

在这里插入图片描述
在比较两个字符串的大小时,会逐个对字符的大小进行比较,直至遇到不相等的字符为止。 上面的示例代码可以这样理解:先比较com1字符串与com2字符串的第1个字符,若相等,再比较第 2个字符,以此类推。由于com2的第4个字符(2)大于com1的第4个字符(1),因此com2字符串 大于com1字符串。

var string = "Hello - Swift"

var startIndex = string.startIndex

var endIndex = string.endIndex

print(string)
print(startIndex)
print(endIndex)

var char = string[string.index(after: startIndex)]

var char2 = string[string.index(before: string.endIndex)]

print(char)
print(char2)

在这里插入图片描述
这里需要注意,startIndex和endIndex获取到的值为Index类型,并不是整数类型,它们不能直接进行加减运算,需要使用相应的方法进行下标的移动操作
index(after:)方法用来获取当前下标的后一位下标,index(before:)方法用来获取当 前下标的前一位下标。也可以通过传入下标范围的方式来截取字符串中的某个子串


var string = "Hello - Swift"
var startIndex = string.startIndex

var endIndex = string.endIndex

var subString = string[startIndex...string.index(startIndex, offsetBy: 4)]
var subString2 = string[string.index(endIndex, offsetBy: -5)..<endIndex]

print(string)
print(startIndex)
print(endIndex)
print(subString)
print(subString2)

在这里插入图片描述
上面的示例代码中,“…”为范围运算符,在后面的章节中会详细介绍,offsetBy参数传入的 是下标移动的位数,若向其中传入正数,则下标向后移动相应位数,若向其中传入负数,下标向前 移动相应位数。使用这种方式来截取字符串十分方便。String类型中还封装了一些方法,可以帮助 开发者便捷地对字符串进行追加、插入、替换、删除等操作,示例如下

var string = "Hello - Swift"
//获取某个子串在父串中的范围
var range = string.range(of: "Hello")
//追加一个字符,此时 string = "Hello-Swfit!"
string.append(Character("!"))
//追加字符串操作,此时string = "Hello-Swift! Hello-World"
string.append(" Hello-World")
//在指定位置插入一个字符,此时string = "Hello-Swift!~ Hello-World"
string.insert("~", at: string.index(string.startIndex, offsetBy: 12))
//在指定位置插入一组字符,此时string = "Hello-Swift!~~~~ Hello-World"
string.insert(contentsOf: ["~","~","~"], at: string.index(string.startIndex,
offsetBy: 12))
//在指定范围替换一个字符串,此时string = "Hi-Swift!~~~~ Hello-World"
string.replaceSubrange(string.startIndex...string.index(string.startIndex,
offsetBy: 4), with: "Hi")
//在指定位置删除一个字符,此时string = "Hi-Swift!~~~~ Hello-Worl"
string.remove(at: string.index(before:string.endIndex)) //删除指定范围的字符,此时string = "Swift!~~~~ Hello-Worl"
string.removeSubrange(string.startIndex...string.index(string.startIndex, offsetBy: 2))
//删除所有字符,此时string = ""
string.removeAll()
var string2 = "My name is Jaki"
print(string2)
//全部转换为大写
string2 = string2.uppercased()
print(string2)
//全部转换为小写
string2 = string2.lowercased()
print(string2)

在这里插入图片描述

//检查字符串是否有 My 前缀
string2.hasPrefix("My")
//检查字符串是否有 jaki 后缀
string2.hasSuffix("jaki")

集合类型

在Swift语言中一共提供了3种集合类型:数组(Array)、集合(Set)和字典(Dictionary)。 数组类型是一种有序集合,放入其中的数据都有一个编号,且编号从0开始依次递增。通过编号, 开发者可以找到Array数组中对应的值。集合是一组无序的数据,其中存入的数据没有编号,开发 者可以使用遍历的方法获取其中所有的数据。集合是一种键值映射结构,其中每存入一个值都要对 应一个特定的键,且键不能重复,开发者通过键可以直接获取到对应的值。Swift官方开发文档中 的一张示例图片可以十分清晰地描述这3种集合类型的异同在这里插入图片描述

数组(Array)类型

数组中能够存放的元素并非只是数字,它可以存放任意类型的数据,但是所有数据的类型必 须统一。在实际开发中,数组中元素的类型决定了数组的类型

//Int整形数组
var array1 : [Int]
var array2 : Array<Int>

上面两行代码都声明了一个Int类型的数组实例,数组的创建可以使用两种方式,一种是使用 数组的构造方法来创建,另一种是使用中括号来快捷创建

var array1 : [Int]
var array2 : Array<Int>
//创建空数组
array1 = []
array2 = Array()
//创建整形数组
array1 = [1, 2, 3]
//通过一组元素创建数组
array2 = Array(arrayLiteral: 1, 2, 3)

和 String 类型类似,空数组的含义幵非是变量为 nil,而是数组中的元素为空,Swift 中只有 Optional 类型的变量可以为 nil。

在Swift语言中,数组采用结构体来实现,对于大量重复元素的数组,开发者可以直接使用快 捷方法来创建

//创建大量有相同元素的数组
//创建有10个String类型元素的数组,并且每个元素都为字符串“Hello”
var array3 = [String](repeating: "Hello", count: 10)
print(array3)
//创建有10个Int类型元素的数组,并且每个元素都是1
var array4 = Array(repeating: 1, count: 10)
print(array4)

在这里插入图片描述
读者需要注意,数组在声明时必须要明确其类型,但是开发者并不一定需要显式地指定类 型,如果数组在声明时也设置了初始值,则编译器会根据赋值类型自动推断出数组的类型
数组 数组中对加法运算符也进行了重载,开发者可以使用“+”进行两个数组的相加,相加的结果即 将第2个数组中的元素拼接到第1个数组后面。需要注意,相加的数组类型必须相同

var array5 = [1, 2, 3] + [4, 5, 6]
print(array5)

数组中提供了许多方法供开发者来获取数组实例的相关信息或者对数组进行增、删、改、查 的操作

print(array.count)
if array.isEmpty {
    
    print("array为空数组")
}
var a = array[0]
print(a)
var subArray = array[0...3]
print(subArray)
var b = array.first
print(b)
var c = array.last
print(c)
array[0] = 0
print(array)
array[0...3] = [1, 2, 3, 4]
print(array)
array.append(10)
print(array)
array.append(contentsOf: [11, 12, 13])
print(array)
array.insert(0, at: 0)
print(array)
array.insert(contentsOf: [-2, -1], at: 0)
print(array)
array.remove(at: 1)
print(array)
array.removeFirst()
print(array)
array.removeLast()
print(array)
array.removeFirst(2)
print(array)
array.removeLast(2)
print(array)
array.removeSubrange(0...2)
print(array)
array.replaceSubrange(0...2, with: [0, 1])
print(array)
array.removeAll()
print(array)
if array.contains(1) {
    
    print(true)
}
print(array)

在这里插入图片描述
这里需要注意,只有当数组实例为变量时,才可以使用增、删、改等方法,常量数组不能进 行与修改相关的操作。

//Int型数组
let arrayLet = [0, 1, 2, 3, 4]
//(Int, Int)型数组
let arrayLet2 = [(1, 2), (2, 3), (3, 4)]
//直接遍历数组
for item in arrayLet {
    
    print(item)
}
//进行数组枚举遍历
for item in arrayLet.enumerated() {
    
    print(item)
}
//进行数组角标遍历
for index in arrayLet2.indices {
    
    print(arrayLet2[index], separator:"")
}

在这里插入图片描述
可以直接对数组实例进行遍历,Swift中的for-in结构和Objective-C中的for-in结构还是有一些区 别的,Swift中的for-in结构在遍历数组时会按照顺序进行遍历。数组实例中还有一个enumerated() 方法,这个方法会返回一个元组集合,将数组的下标和对应元素返回。开发者也可以通过遍历数组 的下标来获取数组中的元素,和String类型不同的是,数组中的下标可以是Int类型,而String中的下 标是严格的Index类型,这里需要注意,不要混淆。

数组类型中有一个 indices 属性,这个属性将返回一个范围(Range),此范围就是数组下标 的范围。
数组类型中还提供了一个排序函数,如果数组中的元素为整型数据,则可以使用系统提供的sorted(by:)方法来进行排序操作,如果是一些自定义的类型,开发者也可以对sorted(by:)方法传入闭 包参数实现新的排序规则,这部分内容会在后面章节中详细介绍。进行数组排序的方法示例代码如 下:

var arraySort = [1, 3, 5, 6, 7]
arraySort = arraySort.sorted(by: >)
print(arraySort)
arraySort = arraySort.sorted(by: <)
print(arraySort)

print(arraySort.max())
print(arraySort.min())

在这里插入图片描述

集合(Set)类型

集合类型不关注元素的顺序,但是其中的元素不可以重复,读者也可以将其理解为一个无序 的集合。与数组一样,集合在声明时必须指定其类型,或者对其赋初值,使得编译器可以自行推断 出集合的类型

var set1 : Set<Int> = [1, 2, 3, 4]
var set2 = Set(arrayLiteral: 1, 2, 3, 4)
var a = set1[set1.startIndex]
var b = set1[set1.index(after: set1.startIndex)]
var c = set1[set1.index(set1.startIndex, offsetBy: 3)]
print(a, b, c)

在这里插入图片描述
由于集合并不关注其中元素的顺序,因此通过下标的方式来取值对集合来说不太有意义,但 是集合类型依然支持通过下标来获取其中的元素
需要注意,集合的下标操作为不可逆的操作,只能向后移动,不能向前移动。
下面这个方法可以获取集合实例中的一些信息


//获取元素个数
set1.count
//判断集合是否为空集合
if set1.isEmpty {
    
print("集合为空") }
//判断集合中是否包含某个元素
if set1.contains(1){
    
print("集合包含") }
//获取集合中的最大值
set1.max()
//获取集合中的最小值
set1.min()

集合同样支持进行增、删、改、查操作

//向集合中插入一个元素
set1.insert(5)
//移除集合中的某个元素
set1.remove(1)
//移除集合中的第一个元素
set1.removeFirst() //移除集合中某个位置的元素
set1.remove(at: set1.firstIndex(of: 3)!)
//移除集合中所有的元素
set1.removeAll()

在使用remove(at:)方法删除集合某个位置的元素时,需要传入一个集合元素的下标值,通过集 合实例的firstIndex(of:)方法可以获取具体某个元素的下标值。需要注意,这个方法将会返回一个 Optional类型的可选值,因为要寻找的元素可能不存在,在使用时,开发者需要对其进行拆包操作。
集合与数组除了有序和无序的区别外,集合还有一个独有的特点:可以进行数学运算,例如 交集运算、并集运算、补集运算等。Swift官方开发文档中的一张图片示意了集合进行数学运算时 的场景在这里插入图片描述
可以看出,集合支持4类数学运算,分别为intersection(交集)运算、 symmetricDifference(交集的补集)运算、union(并集)运算和subtracting(补集)运算。交集运 算的结果为两个集合的交集,交集的补集运算的结果为a集合与b集合的并集除去a集合与b集合的交 集,并集运算的结果为两个集合的并集,补集运算的结果为a集合除去a集合与b集合的交集。上述4 种运算的示例代码如下:

var set3:Set<Int> = [1,2,3,4]
var set4:Set<Int> = [1,2,5,6] //返回交集 {1,2}
var setInter = set3.intersection(set4) //返回交集的补集{3,4,5,6}
var setEx = set3.symmetricDifference(set4) //返回并集{1,2,3,4,5,6}
var setUni = set3.union(set4) //返回第二个集合的补集{3,4}
var setSub = set3.subtracting(set4)

使用比较运算符“==”可以比较两个集合是否相等,当两个集合中的所有元素都相等时,两 个集合才相等。集合中还提供了一些方法用于判断集合间的关系

var set5:Set = [1,2]
var set6:Set = [2,3]
var set7:Set = [1,2,3]
var set8:Set = [1,2,3]
//判断是否是某个集合的子集,set5 是 set7 的子集,返回 ture 
set5.isSubset(of: set7)
//判断是否是某个集合的超集,set7 是 set5 的超集,返回 ture 
set7.isSuperset(of: set5)
//判断是否是某个集合的真子集,set5 是 set7 的真子集,返回 ture 
set5.isStrictSubset(of: set7) //判断是否是某个集合的真超集,set7 不是 set8 的真超集,返回 false 
set7.isStrictSuperset(of: set8)

与数组类似,集合也可以通过for-in遍历的方式来获取所有集合中的数据,可以通过3种方法 来进行遍历:遍历元素、遍历集合的枚举与遍历集合的下标。集合枚举会返回一个元组,元组中 将集合下标和其对应的值一同返回

//遍历元素
for item in set7 {
    
	print(item) 
}
//遍历集合的枚举
for item in set7.enumerated() {
    
	print(item) 
}
//遍历集合的下标
for index in set7.indices {
    
	print(set7[index]) 
}

集合虽然不强调元素顺序,但是在遍历时,开发者可以对其进行排序后再遍历

for item in set7.sorted(by: >) {
    
	print(item) 
}

字典(Dictionary)类型

字典在使用时是由一个索引找到一个结果
这种数据的存储模式被称为键值映射模式,即通过一个确定的键可以找到一个确定的值

//声明字典[param1:param2],这种结构用于表示字典类型,param1 为键类型,param2 为值类型 
var dic1:[Int:String]
//这种方式和[:]效果一样,dic2 与 dic1 为相同的类型
var dic2:Dictionary<Int,String>
//字典创建与赋值
dic1 = [1:"1",2:"2",3:"3"]
dic2 = Dictionary(dictionaryLiteral: (1,"1"),(2,"2"),(3,"3")) //在创建字典时,也可以不显式声明字典的类型,可以通过赋初值的方式来使编译器自动推断 
var dic3 = ["1":"one"]
//创建空字典
var dic4:[Int:Int] = [:]
var dic5:Dictionary<Int,Int> = Dictionary()

字典通过键来找到特定的值,在字典中值可以重复,但是键必须唯一。这样才能 保证一个确定的键能找到一个确定的值,并且如果开发者在字典中创建重复的键,编译器也会报出 错误。
字典类型也支持使用isEmpty与count来判断是否为空并获取元素个数

//获取字典中的元素个数 
dic1.count 
//判断字典是否为空
if dic4.isEmpty{
    
	print("字典为空") 
}

通过具体键可以获取与修改对应的值


//通过键操作值 //获取值
dic1[2]
//修改值 
dic1[1]="0" 
//添加一对新的键值 
dic1[4] = "4"

上面代码中的dic1[1]="0"与dic1[4]="4"实际上完成了相同的操作,可以这样理解:在对某个 键进行赋值时,如果这个键存在,则会进行值的更新,如果这个键不存在,则会添加一对新的键 值。然而在开发中,很多情况下需要对一个存在的键进行更新操作,如果这个键不存在,则不添加 新键值对,要实现这种效果,可以使用字典的更新键值方法

//对键值进行更新 
dic1.updateValue("1", forKey: 1)

updateValue(value:forkey:)方法用于更新一个已经存在的键值对,其中第1个参数为新值,第2 个参数为要更新的键。这个方法在执行时会返回一个Optional类型的值,如果字典中此键存在,则 会更新成功,并将键的旧值包装成Optional值返回,如果此键不存在,则会返回nil。在开发中, 常常使用if-let结构来处理

if let oldValue = dic1.updateValue("One", forKey: 1) {
     print("Old Value is \(oldValue)")
}

其实在通过键来获取字典中的值时,也会返回一个Optional类型的值,如果键不存在,则此 Optional值为nil,因此也可以使用if-let结构来保证程序的安全性

//通过键获取的数据也将返回Optional类型的值,也可以使用
if let if let value = dic2[1] {
    
print("The Value is \(value)") }
下面的方法可以实现对字典中键值对的删除操作:
//通过键删除某个键值对 
dic1.removeValue(forKey: 1) 
//删除所有键值对 
dic1.removeAll()

在对字典进行遍历操作时,可以遍历字典中所有键组成的集合,也可以遍历字典中所有值组 成的集合,通过字典实例的keys属性与values属性分别可以获取字典的所有键与所有值

//通过键来遍历字典
for item in dic2.keys {
    
	print(item) 
}
//通过值来遍历字典
for item in dic2.values {
    
	print(item) 
}
//直接遍历字典
for item in dic2 {
    
	print(item) 
}
for (key,value) in dic2 {
     
	print("\(key):\(value)")
}

也可以直接对字典实例进行遍历,遍历中会返回一个元组类型包装字典的 键和值。
在进行字典键或者值的遍历时,也支持对其进行排序遍历

for item in dic2.keys.dic2.keys.sorted(by: >) {
     print(dic2[item]!)
}

基本运算符与程序流程控制

  • 一元运算符:一元运算符作用于一个操作数,其可以出现在操作数的前面,例如正负运算符 “+”“-”,逻辑非运算符“!”。
  • 二元运算符:二元运算符作用于两个操作数乊间,例如加减运算符“+”“-”等。
  • 三元运算符:三元运算符作用于三个操作数乊间,经典的三元运算符有问号、冎号运算符,
    其可以斱便地实现简单的判断选择结极。
//字符串赋值
var str = "Hello, playground" //整型赋值
var count = 5
//元组赋值
var group = (1,2,"12")
//Bool 赋值
var bol = true

如果要将一个元组中的值依次赋给指定的量值,Swift中还支持使用解构赋值的语法来进行赋值

赋值运算符用于值的传递,其结果是量值被赋了具体的值。相等运算符则用于比较操作, 其会返回一个 Bool 类型的逻辑值
Swift语言从2.2版本之后,删除了自增运算符“++”与自减运算符“–”,目前版本的Swift语言中不可以
使用这两个运算符

空合并运算符

可选值类型是Swift语言的一个独特之处,空合并运算符就是针对可选值类型而设计的运算符

var q:Int? = 8 
var value:Int 
if q != nil {
    
	value = q! 
} else {
    
	value = 0 
}

上面的示例就是一个简单的if-else的选择结构,利用4.1.5小节介绍的条件运算符(三目运算 符)可以将上面的代码简写如下


var q:Int? = 8
var value:Int
value = (q != nil) ? (q!) : 0

使用条件运算符改写后的代码简单很多,Swift语言中还提供了空合并运算符来更加简洁地处 理这种Optional类型值的条件选择结构,空合并运算符由“??”表示,上面的代码可以改写成如下 形式:

//空合并运算符 
var q:Int? = 8 
var value:Int value = q ?? 0

空合并运算符“??”是一个二元运算符,使用空合并运算符改写后的代码更加简洁。其需要两 个操作数,第一个操作数必须为一个Optional值,如果此Optional值不为nil,则将其进行拆包操作, 并作为空合并运算的运算结果。如果此Optional值为nil,则会将第二个操作数作为空合并操作运算 的结果返回。使用空合并操作符来处理有关Optional值的选择逻辑将十分方便

区间运算符

Swift中除了支持Range结构体来描述 范围外,还提供了一个区间运算符来快捷直观地表示范围区间。

//创建范围 >=0 且<=10 的闭区间 
var range1 = 0...10 
//创建范围>=0 且<10 的半开区间 
var range2 = 0..<10

也可以通过“~=”运算符来检查某个数字是否包含于范围中

//8 是否在 range1 中
print(range1 ~= 8) //输出 true

区间运算符常见于for-in循环结构中,开发者常常会使用区间运算符来定义循环次数,示例如 下:

//a...b 为闭区间写法 
for index in 0...3 {
    
	print(index) 
}
//a..<b 为左闭右开区间 
for index in 0..<3 {
    
	print(index) 
}

在 for-in 循环结极中,如果 in 关键字后面是一个集合,则变量 index 会自动获取集合中的元 素;如果 in 关键字后面是一个范围,则 index 获取到的是从左向右依次遍历到的范围索引 数。

循环结构

for-in 循环结构

读者对于for-in结构并不陌生,在前面章节中介绍的很多内容都使用了for-in结构进行演示。如 果读者了解C/Objective-C语言,这里就要注意了,在C/Objective-C语言中也支持for-in循环结构,但 是其被称为快速遍历,用它进行的循环操作是无序的。Swift语言中的for-in结构则强大很多,其可 以进行无序的循环遍历,也可以进行有序的循环遍历

//将打印 1,2,3,4,5 
for index in 1...5 {
    
print(index) }

for-in结构中需要两个参数,第2个参数可以是一个集合类型的实例,也可以是一个范围区间, 第1个参数为捕获参数,每次从第2个参数中遍历出的元素便会赋值给它,开发者在循环结构中可以 直接使用。
在进行for-in循环遍历的时候,开发者并不需要捕获到遍历出的值,可以使用匿名参数来接收, Swift中使用“_”符号来表示匿名参数

//如果不需要获取循环中的循环次序,可以使用如下方式 var sum=0;
for _ in 1...3 {
    
sum += 1 }

对集合的遍历是for-in循环常用的场景之一,这些在前面讲解集合类型的章节中已经详细介绍 过了

//遍历集合类型
var collection1:Array = [1,2,3,4]
var collection2:Dictionary = [1:1,2:2,3:4,4:4] var collection3:Set = [1,2,3,4]
for obj in collection1 {
    
print(obj) }
for (key , value) in collection2 {
     print(key,value)
}
for obj in collection3 {
    
print(obj) }

while 与 repeat-while 条件循环结构

while与repeat-while结构在C/Objective-C语言中也支持,并且功能基本一致,只是Swift语言将 do-while结构修改为repeat-while。
在开发中,经常有条件循环的需求,例如模拟水池蓄水的过程,每次蓄水1/10,当蓄满水后停 止蓄水。while循环结构可以十分方便地创建这类循环代码

var i=0
//当 i 不小于 10 时跳出循环 while i<10 {
    
print("while",i) //进行 i 的自增加 i+=1
}

在while循环结构中,while关键字后面需要填写一个逻辑值或者以逻辑值为结果的表达式作为 循环条件,如果逻辑值为真,则程序会进入while循环体。执行完循环体的代码后进行循环条件的 判断,如果循环条件依然为真,则会再次进入循环体,否则循环结束。由于while循环是根据循环条件来判断是否进入循环体的,如果循环条件一直成立,则会无限循环,因此开发者在使用while 循环的时候,注意要在循环体中对循环条件进行修改,且修改的结果是循环条件不成立,否则会出 现死循环。

//使用 Switch 语句进行元组的匹配 
var tuple = (0,0)
switch tuple {
     //进行完全匹配
case (0,1): 
	print("Sure")
//进行选择性匹配 
case (_,1):
	print("Sim")
//进行元组元素的范围匹配 
case(0...3,0...3):
	print("SIM") 
default:
	print("") }

如以上代码所示,在进行元组的匹配时,有3种方式可以选择:第1种方式是完全匹配,即元 组中所有元素都必须完全相等,才算匹配成功;第2种方式是选择匹配,即开发者只需要指定元组 中的一些元素进行匹配,不需要关心的元素可以使用匿名参数标识符来代替,这种方式下,只要指 定的参数都相等,就算匹配成功;第三种方式是范围匹配,即相应位置指定的范围包含需匹配元组 相应位置的值,就算匹配成功。其中第2种匹配方式可以和第3种匹配方式组合使用
Swift语言中的case子句中还可以捕获switch元组的参数,在相应的case代码块中可以直接使用 捕获到的参数,这在开发中可以简化所编写的代码

var tuple = (1,0) //进行数据绑定

switch tuple {
    
//对元组中的第一个元素进行捕获
case (let a,1):
    print(a)
case (let b,0):
    print(b)
//捕获元组中的两个元素,let(a,b) 与 (let a,let b)意义相同
case let(a,b):
    print(a,b)
default:
    print("")
    
}

这里读者需要注意,要捕获的元素并不能起到匹配的作用,例如元组tuple中有两个元素,如 果case条件为(let a,1),则在进行匹配时会匹配tuple中第2个参数,如果匹配成功,则会将tuple元组 的第1个参数的值传递给a常量,并且执行此case中的代码块,在这个代码块中,开发者可以直接使 用常量a。因此,要捕获的元素在匹配时实际上充当着匿名标识符的作用,如以上代码中的第3个case 子句,其条件为let(a,b),实际上这个条件始终会被匹配成功。并且,如果开发者对元组中的所有元 素都进行了捕获,在代码表现上,可以写作(let a,let b),也可以直接捕获整个元组,写作let(a,b), 这两种方式只是写法上有差异,在使用时并无差别。


var tuple = (0,0) //进行数据绑定
//对于进行了数据捕获的 Switch-case 结构,可以使用 where 关键字来进行条件判断
switch tuple {
    
    case (let a,1):
        print(a)
//当元组中的两个元素都等于 0 时才匹配成功,并且捕获第一个元素的值
    case (let b,0) where b==0:
        print(b) //当元组中的两个元素相同时,才会进入下面的case
    case let(a,b) where a==b:
        print(a,b)
    default:
        print("")
}

Swift 语言中的流程跳转语句

跳转语句可以提前中断循环结构,也可以人为控制选择结构的跳转,使代码的执行更加灵活 多变。Swift中提供了大量的流程跳转语句供开发者使用,熟悉这些语句的结构与特点可以使开发 效率大大提高。Swift中提供的流程跳转语句主要有continue、break、fallthrough、return、throw、guard
continue语句用于循环结构中,其作用是跳过本次循环,直接开始下次循环。这里需要注意, continue的作用并不是跳出循环结构,而是跳过本次循环,直接执行下一个循环周期


for index in 0...9 {
    
    if index == 6 {
    
        continue
    }
    print("第\(index)次循环")
}

在这里插入图片描述
continue语句默认的操作范围直接包含它的这一层循环结构,如果代码中嵌套 了多层循环结构,continue语句会跳过本次循环。那么,如果想要实现不跳过本次循环,而是直接 跳至开发者指定的那一层循环结构

MyLabel:for indexI in 0...2 {
    
    for indexJ in 0...2 {
    
        if indexI == 1 {
    
            continue MyLabel
        }
    print("第\(indexI)\(indexJ)次循环")
    }
}

在这里插入图片描述
以上代码创建了两层循环结构,在内层循环中使用了continue语句进行跳转,MyLabel是外层 循环的标签,因此这里的continue跳转将会跳出indexI等于1时的外层循环,直接开始indexI等于2的 循环操作。

break语句是中断语句,其也可以用于循环结构中,和continue语句不同的是,break语句会直接 中断直接包含它的循环结构,即当循环结构为一层时,如果循环并没有执行完成,则后面所有的循 环都将被跳过。如果有多层循环结构,程序会直接中断直接包含它的循环结构,继续执行该循环结 构外层的循环结构

for index in 0...9 {
    
    if index == 6 {
    
        break
    }
    print("第\(index)次循环")
}

在这里插入图片描述
上面的代码在index等于6时使用了break语句进行中断,第5次循环后的所有打印信息都将被 跳过。break语句默认将中断直接包含它的循环结构,同样也可以使用指定标签的方式来中断指定 的循环结构

MyLabel:for indexI in 0...2 {
    
    for indexJ in 0...2 {
    
        if indexI == 1 {
    
            break MyLabel
        }
    print("第\(indexI)\(indexJ)次循环")  
    }
}

在这里插入图片描述
break语句也可以用于switch结构中。在switch结构中,break语句将直接中断后面所有的匹配过 程,直接跳出switch结构。在Swift语言中,switch-case选择匹配结构默认就是break操作,故开发者 不必手动添加break代码
fallthrough语句是Swift中特有的一种流程控制语句,前面提到过,当Swift语言中的switch-case 结构匹配到一个case后,会自动中断后面所有case的匹配操作,如果在实际开发中需要switch-case 结构不自动进行中断操作,可以使用fallthrough语句


var tuple = (0,0)
switch tuple {
    
    case (0,0):
        print("Sure")
        //fallthrough 会继续执行下面的 case
        fallthrough
    case (_,0):
        print("Sim")
        fallthrough
    case(0...3,0...3):
        print("SIM")
    default:
        print("")
}

在这里插入图片描述
return语句对于读者来说应该十分熟悉,其在函数中用于返回结果值,也可以用于提前结束无 返回值类型的函数。当然,return语句的应用场景不只局限于函数中,在闭包中也可以使用return 进行返回


//有返回值函数的返回
func myFunc()->Int{
    
    return 0
}
//无返回值函数的返回
func myFunc(){
    
    return
}

throw语句用于异常的抛出,throw语句抛出的异常如果不进行捕获处理,也会使程序中断

//定义异常类型
enum MyError:Error{
    
    case errorOne
    case errorTwo
    
}
func newFunc() throws{
    
    //抛出异常
    throw MyError.errorOne
}

guard-else结构语句是Swift 2.0之后新加入的一种语法结构,Swift团队创造它的目的在于使代 码的结构和逻辑更加清晰。在实际开发中,尤其是在函数的编写中,经常会遇到这样的场景:当 参数符合某个条件时,函数才能正常执行,否则直接通过return来终止函数的执行,如果不使用 guard-else结构

函数的基本应用

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

闭包的语法结构

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_61196797/article/details/131109186

智能推荐

python简易爬虫v1.0-程序员宅基地

文章浏览阅读1.8k次,点赞4次,收藏6次。python简易爬虫v1.0作者:William Ma (the_CoderWM)进阶python的首秀,大部分童鞋肯定是做个简单的爬虫吧,众所周知,爬虫需要各种各样的第三方库,例如scrapy, bs4, requests, urllib3等等。此处,我们先从最简单的爬虫开始。首先,我们需要安装两个第三方库:requests和bs4。在cmd中输入以下代码:pip install requestspip install bs4等安装成功后,就可以进入pycharm来写爬虫了。爬

安装flask后vim出现:error detected while processing /home/zww/.vim/ftplugin/python/pyflakes.vim:line 28_freetorn.vim-程序员宅基地

文章浏览阅读2.6k次。解决方法:解决方法可以去github重新下载一个pyflakes.vim。执行如下命令git clone --recursive git://github.com/kevinw/pyflakes-vim.git然后进入git克降目录,./pyflakes-vim/ftplugin,通过如下命令将python目录下的所有文件复制到~/.vim/ftplugin目录下即可。cp -R ...._freetorn.vim

HIT CSAPP大作业:程序人生—Hello‘s P2P-程序员宅基地

文章浏览阅读210次,点赞7次,收藏3次。本文简述了hello.c源程序的预处理、编译、汇编、链接和运行的主要过程,以及hello程序的进程管理、存储管理与I/O管理,通过hello.c这一程序周期的描述,对程序的编译、加载、运行有了初步的了解。_hit csapp

18个顶级人工智能平台-程序员宅基地

文章浏览阅读1w次,点赞2次,收藏27次。来源:机器人小妹  很多时候企业拥有重复,乏味且困难的工作流程,这些流程往往会减慢生产速度并增加运营成本。为了降低生产成本,企业别无选择,只能自动化某些功能以降低生产成本。  通过数字化..._人工智能平台

electron热加载_electron-reloader-程序员宅基地

文章浏览阅读2.2k次。热加载能够在每次保存修改的代码后自动刷新 electron 应用界面,而不必每次去手动操作重新运行,这极大的提升了开发效率。安装 electron 热加载插件热加载虽然很方便,但是不是每个 electron 项目必须的,所以想要舒服的开发 electron 就只能给 electron 项目单独的安装热加载插件[electron-reloader]:// 在项目的根目录下安装 electron-reloader,国内建议使用 cnpm 代替 npmnpm install electron-relo._electron-reloader

android 11.0 去掉recovery模式UI页面的选项_android recovery 删除 部分菜单-程序员宅基地

文章浏览阅读942次。在11.0 进行定制化开发,会根据需要去掉recovery模式的一些选项 就是在device.cpp去掉一些选项就可以了。_android recovery 删除 部分菜单

随便推点

echart省会流向图(物流运输、地图)_java+echart地图+物流跟踪-程序员宅基地

文章浏览阅读2.2k次,点赞2次,收藏6次。继续上次的echart博客,由于省会流向图是从echart画廊中直接取来的。所以直接上代码<!DOCTYPE html><html><head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" /&_java+echart地图+物流跟踪

Ceph源码解析:读写流程_ceph 发送数据到其他副本的源码-程序员宅基地

文章浏览阅读1.4k次。一、OSD模块简介1.1 消息封装:在OSD上发送和接收信息。cluster_messenger -与其它OSDs和monitors沟通client_messenger -与客户端沟通1.2 消息调度:Dispatcher类,主要负责消息分类1.3 工作队列:1.3.1 OpWQ: 处理ops(从客户端)和sub ops(从其他的OSD)。运行在op_tp线程池。1...._ceph 发送数据到其他副本的源码

进程调度(一)——FIFO算法_进程调度fifo算法代码-程序员宅基地

文章浏览阅读7.9k次,点赞3次,收藏22次。一 定义这是最早出现的置换算法。该算法总是淘汰最先进入内存的页面,即选择在内存中驻留时间最久的页面予以淘汰。该算法实现简单,只需把一个进程已调入内存的页面,按先后次序链接成一个队列,并设置一个指针,称为替换指针,使它总是指向最老的页面。但该算法与进程实际运行的规律不相适应,因为在进程中,有些页面经常被访问,比如,含有全局变量、常用函数、例程等的页面,FIFO 算法并不能保证这些页面不被淘汰。这里,我_进程调度fifo算法代码

mysql rownum写法_mysql应用之类似oracle rownum写法-程序员宅基地

文章浏览阅读133次。rownum是oracle才有的写法,rownum在oracle中可以用于取第一条数据,或者批量写数据时限定批量写的数量等mysql取第一条数据写法SELECT * FROM t order by id LIMIT 1;oracle取第一条数据写法SELECT * FROM t where rownum =1 order by id;ok,上面是mysql和oracle取第一条数据的写法对比,不过..._mysql 替换@rownum的写法

eclipse安装教程_ecjelm-程序员宅基地

文章浏览阅读790次,点赞3次,收藏4次。官网下载下载链接:http://www.eclipse.org/downloads/点击Download下载完成后双击运行我选择第2个,看自己需要(我选择企业级应用,如果只是单纯学习java选第一个就行)进入下一步后选择jre和安装路径修改jvm/jre的时候也可以选择本地的(点后面的文件夹进去),但是我们没有11版本的,所以还是用他的吧选择接受安装中安装过程中如果有其他界面弹出就点accept就行..._ecjelm

Linux常用网络命令_ifconfig 删除vlan-程序员宅基地

文章浏览阅读245次。原文链接:https://linux.cn/article-7801-1.htmlifconfigping &lt;IP地址&gt;:发送ICMP echo消息到某个主机traceroute &lt;IP地址&gt;:用于跟踪IP包的路由路由:netstat -r: 打印路由表route add :添加静态路由路径routed:控制动态路由的BSD守护程序。运行RIP路由协议gat..._ifconfig 删除vlan