Swift开发——循环执行方式

简介: Swift语言中的循环主要包括`for-in`和`while`结构。`for-in`适用于遍历数字区间、字符串和字典,支持使用`stride`函数定制步进。字典遍历时,可以用二元元组`(k, v)`访问键值对。`while`循环有标准形式和`repeat-while`形式,确保至少执行一次循环体。程序示例展示了`for-in`和不同`while`结构的用法,包括计算阶乘、奇数和、加密字符串以及最大公约数和最小公倍数。

image.png


本文将介绍 Swift 语言的循环执行方式



# 01、循环执行方式



在Swift语言中,主要有两种循环执行控制方式: for-in结构和while结构。while结构又细分为当型while结构和直到型while结构,后者称为repeat-while结构。下面首先介绍for-in结构。

循环控制方式for-in结构可用于区间中的整数值遍历、字符串中的字符遍历、字典中的元素遍历等,常用的形式如下。

(1) 典型for-in结构。

image.png


上述for-in结构中,遍历“范围”中的各个“元素”,对于每个“元素”执行“语句组”一次。这里无须为“元素”定义变量类型,自动根据“范围”中的数组类型设定“元素”的数据类型。

如果“元素”使用“_”替换,则表示不关注“范围”中的具体元素,只关注循环次数。表示“范围”的方法可借助运算符“...”和“..<”,或者使用函数stride(from:to:by:)或stride(from:through:by:)实现,两个stride的区别在于前者不包含“to”参数指定的边界,而后者包含“through”参数指定的边界。例如: stride(from:1, to:10, by:3)表示1~10、步长为3生成的序列,即1、4、7,不包含10; stride(from:1, through:10, by:3)表示1~10、步长为3生成的序列,即1、4、7、10,包含10。

for-in结构中的“范围”可以为字符串或字典。

(2) 用于字典遍历的for-in结构。

image.png

在上述for-in结构中,使用“二元元组”作为字典中每个元素的返回值,例如,将二元元组表示为“(k,v)”,则k将对应着字典元素的键值,v将对应着同一个字典元素的值。如果k用“”表示,则将只关心字典元素的值,而不关心它的键值。如果v用“”表示,则将只关心字典元素的键值,而不关心它的值。

程序段1介绍了for-in结构的用法。

程序段1for-in结构的用法实例

image.png


image.png


image.png


程序段1的执行结果如图1所示。

image.png


■ 图3-5程序段3-11的执行结果



下面结合图3-5介绍程序段3-11的执行过程。在程序段3-11中,第2行“var s=1”定义整型变量s,赋初值为1。第3~6行为一个for-in结构,第3行“for e in 1...10”表示e在1~10的10个整数上遍历,即e依次取值1、2、……、10,循环执行第5行“s = e”,这里为计算10的阶乘。第7行“print("10!=",s)”输出10的阶乘的值。

第9行“s=1”令变量s的值为1。第10~13行为一个for-in结构,第10行“for in 1...10”中使用“”作为循环变量,没有指定循环变量的名称,表示该循环只关注循环次数,这里循环10次,计算第12行“s
= 2”,即计算2的10次方。第14行“print("2^10=",s)”输出2的10次方的值。

第16行“s=0”将0赋给变量s。第17~20行为一个for-in结构,第17行“for e in stride(from:1, to:100, by:2)”这里e遍历的序列为1、3、5、……、99,对于每个遍历值执行第19行“s+=e”,即计算100以内的正奇数的和。第21行“print("1+3+...+99=",s)”输出字符串“1+3+...+99=”和s的值。这里循环变量e的作用范围为for-in结构,故在其他的for-in结构中仍然可以使用同名的局部变量e。

第23~32行实现了与第16~21行相同的功能,这里为演示continue语句的用法。第23行“s=0”将0赋给变量s。第24~31行为一个for-in结构,第24行“for e in stride(from:1, through:100, by:1)”表示循环变量e在范围1、2、……、100上遍历取值,对每个e,执行第26~30行,第26~29行为一个if结构,第26行“if e % 2 == 0”如果e为偶数,则执行第28行“continue”,表示跳过for-in结构中continue后面的语句回到第24行执行条件判断,这里跳过第30行回到第24行,即忽略循环变量e为偶数的情况。第32行“print("1+3+...+99=",s)”输出字符串“1+3+...+99=”和s的值。

第34~47行实现了与第16~21行相同的功能,即计算100以内正奇数的和,这里为了演示break语句的用法。第41~44行为一个if结构,如果第41行“if e>=100”的条件为真,则执行第43行break语句,跳出它所在的for-in结构,这里跳转到第47行执行。

现在总结一下continue和break的特点: ①continue和break均可以用于if、switch、for-in和while结构中; ②在循环体中遇到continue,将跳过循环体内continue之后的语句,转到循环开头执行条件判断,开始下一次循环; ③在循环体内遇到break语句,将跳出该循环体,转到循环体外的下一条语句执行; ④对于嵌套的循环体而言,continue和break语句仅对它所在的循环体有效,当有多个嵌套的循环体时,为了明确continue和break作用的循环体,可以为它们所在的循环体开头添加标号,指示continue和break的跳转,这个仅是为了方便程序阅读,第49~62行中演示了这种用法。

第49~62行实现了与第16~21行相同的功能。第50~61行为一个for-in结构,第50行“mylabel:for e in 1...100”在for循环体头部添加了标号mylabel,第54行continue mylabel表示continue执行时要跳转的标号为mylabel; 第58行break mylabel表示break要执行时跳出的循环体为mylabel指示的循环体。

第64行“let p="helloworld"”定义常量p,赋值为“helloworld”。第65行“var c:String=""”定义字符串变量c,赋值为空串。第66行“print("plain=",p)”输出字符串“plain=”和字符串p的值。第67~70行为一个for-in结构,这里实现了凯撒密码,即一个字符用其后的第4个字符替换,第67行“for e in p.unicodeScalars”表示循环变量e在p的Unicode码形式的字符串中遍历各个字符,对于每个e,执行第69行“c+=String(UnicodeScalar((e.value-97+4)%26+97)!)”,这里“e.value”返回e的ASCII值,97为字符a的ASCII值,UnicodeScalar函数返回以整数值参数作为ASCII值对应的字符,这里将每个e变换后的字符转换为字符串添加到c的尾部。第71行“print("cipher=",c)”,输出加密后的密文文本c。第69行中的97可以使用“UnicodeScalar("a").value”替换,可避免去查字符a的ASCII值,这里,“UnicodeScalar("a").value”返回字符a的ASCII值。

第73行“let dic=["Apple":3.5,"Pear":2.7,"Banana":5.2]”定义字典dic。第74~77行为一个for-in结构,第74行“for (k,v) in dic”中,元组(k,v)遍历dic字典的每个元素,其中,k存储遍历到的字典元素的键值,v存储遍历到的字典元素的值,对于每个元组(k,v),执行第76行“print(k,v,terminator:",")”,输出遍历到的键值对。第78行“print()”输出一个空行。

第80行“var t=0.0”定义双精度浮点型变量t,赋值为0.0。第81~84行为一个for-in结构,第81行“for(_,v) in dic”中,只关注从字典dic中遍历到的元素的值,将这个值赋给v,对于每次遍历,执行第83行“t+=v”,这里表示计算字典中所有水果的单价和。第85行“print("Total price:",t)”输出字符串“Total price:”和t的值。

上述介绍的for-in结构的特点在于循环变量的取值范围是确定的,可以准确地推断出循环的次数。而当循环次数不可知时,一般不使用for-in结构,而使用while循环控制结构。while结构分为标准while结构和repeat-while结构两种,其语法如下。

(1) 标准while结构,即当型while结构。

image.png


在上述结构中,当“条件表达式”为真时,循环执行“条件表达式为真时执行的语句组”,直到“条件表达式”为假时跳出while循环体。在“条件表达式为真时执行的语句组”中,一般包含有调整“条件表达式”结果的语句。在标准while结构中,如果“条件表达式”为假,则“条件表达式为真时执行的语句组”可能一次也得不到执行。

(2) repeat-while结构,即直到型while结构。

image.png


在上述结构中,先执行一次“语句组”,再判断“条件表达式”的值,若其为真,则循环执行“语句组”,直到“条件表达式”为假,跳出repeat-while循环体。在repeat-while结构中,表示循环体的“语句组”至少可以被执行一次。

程序段2介绍了while结构的用法,实现了欧几里得求两个整数的最大公约数和最小公倍数的算法。欧几里得算法的基本原理: 设a和b为两个整数,不妨设a>b,则gcd(a,b)=gcd(b, a mod b),即a与b的最大公约数等于b与a模b的最大公约数,通过反复求模运算,最后可以表示为gcd(r,0),则r为a与b的最大公约数,最小公倍数为a*b/r。现在发现这个2000多年前的算法是求两数的最大公约数最快的方法。

程序段 2 while 结构用法实例

image.png


image.png


程序段2的执行结果如图2所示。

image.png


■ 图2 程序段2的执行结果

下面结合图2介绍程序段2的执行过程。在程序段3-12中,第3行“var a0=6525”定义整型变量a0,赋初值为6525。第4行“var b0=81450”定义整型变量b0,赋初值为81450。第5行“var a,b:Int”定义整型变量a和b。

第6~9行为一个if结构,第6行“if a0”若a0小于b0,则执行第8行“(a0,b0)=(b0,a0)”将a0和b0的值对换。第10行“(a,b)=(a0,b0)”将a0赋给a,将b0赋给b。

第11行“var r=1”定义整型变量r,赋初值为1。第12~17行为一个while结构,实现欧几里得算法,第12行“while r>0”当r大于0时,循环执行第14~16行,这里的r保存a除以b的余数,如第14行“r=a % b”所示,然后,第15行“a=b”将b赋给a,第16行“b=r”将r赋给b,进行下一次循环,直到余数r为0。第18行“print("gcd(\(a0),\(b0))=\(a)")”输出a0和b0的最大公约数,第19行“print("lcm(\(a0),\(b0))=\(a0*b0/a)")”输出a0和b0的最小公倍数。

第21~29行实现了与第10~19行相同的功能,这里使用了repeat-while结构。第21行“(a,b)=(a0,b0)”将a0赋给a,将b0赋给b。第22~27行为一个repeat-while结构,循环执行第24~26行直到r小于或等于0。第28、29行依次输出a0和b0的最大公约数和最小公倍数。

第31~43行实现了与第10~19行相同的功能。这里使用了while结构,第31行“(a,b)=(a0,b0)”将a0赋给a,将b0赋给b; 第32行“while true”表示这是一个无限循环,循环执行第34~40行,在无限循环体中,添加了第37~40行的一个if结构,判断r的值是否为0(第37行“if r==0”),如果r为0,则执行第39行break,跳出while循环体,跳至第42行执行,第42行“print("gcd(\(a0),\(b0))=\(a)")”输出a0和b0的最大公约数; 第43行“print("lcm(\(a0),\(b0))=\(a0*b0/a)")”输出a0和b0的最小公倍数。

目录
相关文章
|
3天前
|
安全 编译器 Swift
苹果重磅发布Swift 6:在 Swift 6 中如何实现并发开发?相比Swift 5.5 有哪些重磅升级?
Swift 6 强化了并发编程,引入结构化并发、任务、执行器、隔离、同步原语、类型化错误处理和取消超时功能。对比Swift 5.5,它默认启用全面并发检查,改进错误处理,增加了隔离区域、类型化抛出、包迭代等新特性,优化了性能并更新了库。
12 2
|
26天前
|
数据可视化 数据处理 Swift
Swift开发——简单App设计
SwiftUI教程概述:简化App设计,通过代码展示了如何创建一个计算两个数之和的界面。工程`MyCh0902`包含`ContentView.swift`,其中定义了`ContentView`和`MyView`结构体。`MyView`负责界面布局,使用`VStack`和`HStack`组织元素,如`TextField`和`Button`。点击`Button`调用`calc`方法处理输入并更新结果。界面设计可在Xcode的Inspector窗口中可视化配置。推荐将界面逻辑移到单独的`MyView.swift`文件中以清晰分离视图设计。
191 1
Swift开发——简单App设计
|
1月前
|
存储 Swift 索引
Swift开发——索引器扩展
扩展用于向已存在的类型(例如,类、结构体、枚举和协议等)中添加新的功能,扩展甚至可以向系统类型(包括无法查阅代码的类型)中添加新的功能,但是扩展不能覆盖原类型中已有的方法,扩展也不能向类中添加新的存储属性。
38 6
Swift开发——索引器扩展
|
11天前
|
安全 编译器 Swift
探索iOS开发:Swift语言的现代魔法
【7月更文挑战第11天】本文深入探讨了Swift编程语言,它如何革新iOS开发领域,以及它为开发者带来的独特优势。我们将从Swift的基础语法出发,通过实际案例分析其性能优化技巧,最后讨论Swift在跨平台开发中的潜力。文章旨在为读者提供一个全面而深入的视角,了解Swift不仅仅是一门语言,更是一种推动创新的力量。
|
1月前
|
存储 Swift
Swift开发——属性检查器
Swift中的属性检查器(willSet, didSet)允许在设置存储属性值前后执行代码。在类`Circle`中,属性`radius`使用属性观察器:willSet在赋值前检查值,若值为负则打印警告;didSet在赋值后比较新旧值,根据变化输出相应信息。在实例`c`中,`radius`从-5变为0时,输出“Input value is negative.”和“The circle gets smaller.”;从0变为10时,输出“Input value is normal.”和“The circle gets larger.”。
184 4
Swift开发——属性检查器
|
1月前
|
Swift C++ 索引
Swift开发——简单函数实例
函数是编程的基础,用于封装特定功能的代码。它们有关键词func、函数名、参数列表(可为空)和返回类型。多返回值可通过元组、数组、inout参数或可选类型实现。例如,返回元组 `(value1, value2)`,数组 `[value1, value2]` 或使用可选数组 `[[Double]]?`。函数可以作为其他函数的参数,类似闭包或Lambda表达式。在Swift中,示例展示了通过元组、带索引的元组、数组和可选类型返回多个值的函数。还演示了如何使用inout参数交换变量值。
30 5
Swift开发——简单函数实例
|
1月前
|
存储 Swift
Swift开发——弱占用
Swift的自动引用计数(ARC)管理类实例内存,通过强引用保持实例存活。当出现强引用循环时,可使用`weak`关键字创建弱引用,避免阻止实例释放。弱引用在不再被强引用时导致对象立即释放。示例中,添加`weak`至`author`和`book`变量防止引用循环,使得两者析构器均执行,释放内存。图2展示了弱引用结构,当解除所有强引用后,ARC自动释放实例,调用析构器。
185 1
Swift开发——弱占用
|
1月前
|
存储 程序员 Swift
Swift开发——存储属性与计算属性
Swift推荐使用结构体进行开发,结构体支持属性和方法,且作为值类型。结构体属性包括存储属性(如radius)和计算属性(如r),计算属性不存储值,类似方法。结构体用`struct`定义,命名遵循大驼峰规则。实例名遵循小驼峰规则。属性可在结构体中任意位置定义,静态属性用`static`。存储属性可为`lazy`实现懒加载。结构体实例通过`.`访问属性和方法,静态属性和方法用`结构体名.`访问。计算属性可读写,可通过`get`和`set`定义。程序段1展示了结构体Point和Circle的属性和方法,包括私有属性、只读计算属性、可读写计算属性及`mutating`方法。
14 0
Swift开发——存储属性与计算属性
|
1月前
|
Swift 索引
Swift开发——元组
Swift中的元组是一种数据结构,用于组合不同类型的值。它们不是独立的数据类型,而是以有序序列形式存在,用圆括号括起,元素间用逗号分隔。元组可以有任意数量和类型的元素,可变性取决于其定义。常用于函数返回多个值。示例代码展示了元组的创建、访问、解包及赋值。元组可以通过标签来标识元素,支持嵌套和比较。在函数返回值和并行赋值场景中,元组特别有用。
32 0
Swift开发——元组
|
Swift
7.Swift学习之循环
循环的介绍 在开发中经常会用到循环 常见C/OC的循环有:for/while/do while. Swift中对应的为:for/while/repeat while.
942 0