本篇是我在学完一遍基础语法知识的时候,第一遍复习,我一遍梳理一遍记录的笔记。同时分享给像我一样在学习swift 的猿友们。
本篇可能过于冗长、所以所有的参考资料都分模块的写在palyground 里,上传在github 里,地址:https://github.com/NIUXINGJIAN/SWIFT_PLAYGROUND.git
本篇内含有部分的 Markdown 语法,因为草稿写在简书里<我的简书链接>,这里直接粘贴复制一下,不懂Markdown语法的可以去间书里查看。
- ** 导入模块与框架**
我们可以使用 import 语句来引入任何的 Objective-C 框架(或 C 库)到 Swift 程序中。例如 import UIKit 语句导入了使用了 UIKit 库和API,我们可以在 Swift 程序中使用他们。
- ** 注释** swift 的注释与 C 语言的及其的相似;单行注释以两个反斜线开头; 多行注释以 与 OC 一样的,多行注释内还可以嵌套多行注释。
- ** 分割号 “;” **
对于 分割号 ,如果代码是一行的话,可以不写分割号,但是代码是多行的话,就必须要写分割号。
- ** 标记** Swift 程序由多种标记组成,标记可以是单词,标识符,常量,字符串或符号。
- ** 标识符**
标识符就是给变量、常量、方法、函数、枚举、结构体、类、协议等指定的名字。构成标识符的字母均有一定的规范,Swift语言中标识符的命名规则如下: 区分大小写,Myname与myname是两个不同的标识符;
标识符首字符可以以下划线(_)或者字母开始,但不能是数字; 标识符中其他字符可以是下划线(_)、字母或数字。 注意:Swift中的字母采用的是Unicode编码[1]。Unicode叫做统一编码制,它包含了亚洲文字编码,如中文、日文、韩文等字符,甚至是我们在聊天工具中使用的表情符号 如果一定要使用关键字作为标识符,可以在关键字前后添加重音符号(`)
- ** 关键字**
1、与声明有关的关键字 class 、deinit、 enum、 extension、 func 、import、 init 、internal、 let 、operator 、private、protocol、public 、static 、struct、 subscript、typealias 、var 2、与语句有关的关键字
break 、case 、continue 、default、do 、else 、fallthrough 、for 、if 、in 、return 、switch、where 、while 3、表达式和类型关键字
as 、dynamicType、 false、 is、nil 、self 、Self 、super、 true、 _COLUMN_ 、_FILE_ 、_FUNCTION_ 、_LINE_ 4、在特定上下文中使用的关键字
associativity 、convenience 、dynamic 、didSet 、final 、get、 infix 、inout、lazy 、left 、mutating 、none、nonmutating 、optional 、override 、postfix 、precedence 、prefix 、Protocol 、required、 right 、set、 Type 、unowned、weak 、willSet
- ** 空格 **
swift 的空格: Swift语言并不是像C/C++,Java那样完全忽视空格,Swift对空格的使用有一定的要求,但是又不像Python对缩进的要求那么严格。 在Swift中,运算符不能直接跟在变量或常量的后面。例如下面的代码会报错:
eg: 下面是错误的写法: let a= 3 + 4 let a = 3+ 4 let a = 3 +4
下面是正确的写法 let a = 3+4 let a = 3 + 4 print(a)
- ** 字面量 **
Swift 字面量: 所谓字面量,就是指像特定的数字,字符串或者是布尔值这样,能够直接了当地指出自己的类型并为变量进行赋值的值。比如在下面:
42 // 整型字面量 3.14159 // 浮点型字面量 "Hello, world!" // 字符串型字面量 true // 布尔型字面量
- ** 类型转换 **
// let cannotBeNegative: UInt8 = -1 ;UInt8 类型不能存储负数,所以会报错 // let tooBig: Int8 = Int8.max + 1; Int8 类型不能存储超过最大值的数,所以会报错
let twoThousand: UInt16 = 2_000 let one: UInt8 = 1 let twoThousandAndOne = twoThousand + UInt16(one)// 使用了强制转换为相同类型数据,否则编译错误 //SomeType(ofInitialValue) 是调用 Swift 构造器并传入一个初始值的默认方法。 我们可以扩展现有的类型来让它 可以接收其他类型的值(包括自定义类型)
eg: 整数和浮点数的转换必须显式指定类型: let three = 3let pointOneFourOneFiveNine = 0.14159let pi = Double(three) + pointOneFourOneFiveNine// pi 等于 3.14159,所以被推测为 Double 类型
#二、数据类型
基本的数据类型,包括整形Int、浮点数Double和Float、布尔类型Bool以及字符串类型String。此外,Swift还提供了其他更强大数据类型, Optional, Array, Dictionary, Struct, 和 Class 等。
- ** Swift 内置数据类型:**
在我们使用任何程序语言编程时,需要使用各种数据类型来存储不同的信息。 变量的数据类型决定了如何将代表这些值的位存储到计算机的内存中。在声明变量时也可指定它的数据类型。 所有变量都具有数据类型,以决定能够存储哪种数据。
Swift 提供了非常丰富的数据类型,以下列出了常用了几种数据类型:
- ** 内置数据类型 Int**
一般来说,你不需要专门指定整数的长度。Swift 提供了一个特殊的整数类型Int,长度与当前平台的原生字长相同: 在32位平台上,Int和Int32长度相同。 在64位平台上,Int和Int64长度相同。 除非你需要特定长度的整数,一般来说使用Int就够了。这可以提高代码一致性和可复用性。即使是在32位平台上,Int可以存储的整数范围也可以达到-2,147,483,648~2,147,483,647,大多数时候这已经足够大了。
- ** 内置数据类型 UInt **
Swift 也提供了一个特殊的无符号类型UInt,长度与当前平台的原生字长相同: 在32位平台上,UInt和UInt32长度相同。 在64位平台上,UInt和UInt64长度相同。 注意: 尽量不要使用UInt,除非你真的需要存储一个和当前平台原生字长相同的无符号整数。除了这种情况,最好使用Int,即使你要存储的值已知是非负的。统一使用Int可以提高代码的可复用性,避免不同类型数字之间的转换,并且匹配数字的类型推断。
- ** 内置数据类型 浮点数 float 、double **
浮点数: 浮点数是有小数部分的数字,比如3.14159,0.1和-273.15。 浮点类型比整数类型表示的范围更大,可以存储比Int类型更大或者更小的数字。
Swift 提供了两种有符号浮点数类型: Double表示64位浮点数。当你需要存储很大或者很高精度的浮点数时请使用此类型。 Float表示32位浮点数。精度要求不高的话可以使用此类型。
注意: Double精确度很高,至少有15位数字,而Float最少只有6位数字。选择哪个类型取决于你的代码需要处理的值的范围。
- ** 内置数据类型 (布尔值 Boolean)** Swift 有一个基本的布尔(Boolean)类型,叫做Bool。布尔值指逻辑上的值,因为它们只能是真或者假。Swift 有两个布尔常量,true和false。
- ** 内置数据类型 (字符串、字符 ) **
字符串是字符的序列集合。如:"hello world" 字符指的是单个字母。
内置的数据类型 (optionals 可选类型) 使用可选类型 (optionals)来处理值可能缺失的情况。可选类型表示有值或没有值。
- ** 内置的数据类型 (数值范围)**
下面显示了不同变量类型内存的存储空间,及变量类型的最大最小值:
类型 大小(字节) 区间值 Int8 1 字节 -127 到 127 UInt8 1 字节 0 到 255 Int32 4 字节 -2147483648 到 2147483647 UInt32 4 字节 0 到 4294967295 Int64 8 字节 -9223372036854775808 到 9223372036854775807 UInt64 8 字节 0 到 18446744073709551615 Float 4 字节 1.2E-38 到 3.4E+38 (~6 digits) Double 8 字节 2.3E-308 到 1.7E+308 (~15 digits)
- ** 内置数据类型 (类型别名)**
类型别名对当前的类型定义了另一个名字,类型别名通过使用 typealias 关键字来定义。语法格式如下: typealias newname = type 例如以下定义了 Int 的类型别名为 Feet: typealias Feet = Int 现在,我们可以通过别名来定义变量: import Cocoa
typealias Feet = Int var distance: Feet = 100 print(distance)
- ** 内置数据类型 (类型安全)**
Swift 是一个类型安全(type safe)的语言。 由于 Swift 是类型安全的,所以它会在编译你的代码时进行类型检查(type checks),并把不匹配的类型标记为错误。这可以让你在开发的时候尽早发现并修复错误。 下面的程序就会报错。 var varA = 42 varA = "this is hello" print(varA)
- ** 内置数据类型 (类型的推断)** 当你要处理不同类型的值时,类型检查可以帮你避免错误。然而,这并不是说你每次声明常量和变量的时候都需要显式指定类型。 如果你没有显式指定类型,Swift 会使用类型推断(type inference)来选择合适的类型。 例如,如果你给一个新常量赋值42并且没有标明类型,Swift 可以推断出常量类型是Int,因为你给它赋的初始值看起来像一个整数: let meaningOfLife = 42 // meaningOfLife 会被推测为 Int 类型 同理,如果你没有给浮点字面量标明类型,Swift 会推断你想要的是Double: let pi = 3.14159 // pi 会被推测为 Double 类型 当推断浮点数的类型时,Swift 总是会选择Double而不是Float。 如果表达式中同时出现了整数和浮点数,会被推断为Double类型: let anotherPi = 3 + 0.14159 // anotherPi 会被推测为 Double 类型 原始值3没有显式声明类型,而表达式中出现了一个浮点字面量,所以表达式会被推断为Double类型。
- ** Swift 还提供了下面的数据类型 **
Swift 包含了 C 和 Objective-C 上所有基础数据类型, 表示整型值; 和 表示浮点 型值; 是布尔型值; 是文本型数据。 Swift 还提供了三个基本的集合类型 NSary,NSSet , 和 NSDictionary。
除了我们熟悉的类型,Swift 还增加了 Objective-C 中没有的高阶数据类型比如元组(Tuple)。元组可以让你创建或者传递一组数据,比如作为函数的返回值时,你可以用一个元组可以返回多个值。元组是把多个值组合成一个复合值。元组内的值可以是任意类型,并不要求是相同类型。我们可以根据需要任意的组装元祖数据。
Swift 还增加了可选(Optional)类型,用于处理值缺失的情况。可选表示 “那儿有一个值,并且它等于 x ”或者 “那儿没有值” 。可选有点像在 Objective-C 中使用 ,但是它可以用在任何类型上,不仅仅是类。可选类型比 Objective-C 中的 指针更加安全也更具表现力,它是 Swift 许多强大特性的重要组成部分。
#三、变量、常量
变量是一种使用方便的占位符,用于引用计算机内存地址。Swift 每个变量都指定了特定的类型,该类型决定了变量占用内存的大小,不同的数据类型也决定可存储值的范围。
- ** 变量的声明 **
变量声明意思是告诉编译器在内存中的哪个位置上为变量创建多大的存储空间。 在使用变量前,你需要使用 var 关键字声明它,如下所示: var varA = 42 print(varA)
- ** 变量命名**
变量名可以由字母,数字和下划线组成。 变量名需要以字母或下划线开始。 Swift 是一个区分大小写的语言,所以字母大写与小写是不一样的。 变量名也可以使用简单的 Unicode 字符,如下实例:
var uncodeName = "NJW" var ? = "?" var ? = ? print(?,?)
- ** 类型标注**
当你声明常量或者变量的时候可以加上类型标注(type annotation),说明常量或者变量中要存储的值的类 型。如果要添加类型标注,需要在常量或者变量名后面加上一个冒号和空格,然后加上类型名称。
var welcomeMessage: String 这个例子给 welcomeMessage 变量添加了类型标注,表示这个变量可以存储 String 类型的值: 声明中的冒号代表着“是...类型”,所以这行代码可以被理解为: “声明一个类型为 String ,名字为 welcomeMessage 的变量。”
在上面的例子中,没有给 赋初始值,所以变量 的类型是通过一个类型标注指定的,而不是通过初始值推断的。
常量可以是任何的数据类型如:整型常量,浮点型常量,字符常量或字符串常量。同样也有枚举类型的常量。常量类似于变量,区别在于常量的值一旦设定就不能改变,而变量的值可以随意更改。同时,你也不能将常量与变量进行互转。
常量与变量名不能包含数学符号,箭头,保留的(或者非法的)Unicode 码位,连线与制表符。也不能以数字开 头,但是可以在常量与变量名的其他地方包含数字。 - ** 常量的声明**
常量 的声明 一般使用 let 来声明,语法如下: let constantName = <initial value>
// eg: let constA = 42 print(constA)
#四、可选类型 (Optionals)
Swift 的可选(Optional)类型,用于处理值缺失的情况。可选表示"那儿有一个值,并且它等于 x "或者"那儿没有值"。
Swfit语言定义后缀?作为命名类型Optional的简写,换句话说,以下两种声明是相等的: var optionalInteger: Int? var optionalInteger: Optional<Int> 在这两种情况下,变量optionalInteger都是可选整数类型。注意,在类型和?之间没有空格。
Optional 是一个含有两种情况的枚举,None和Some(T),用来表示可能有或可能没有值。任何类型都可以明确声明为(或者隐式转换)可选类型。当声明一个可选类型的时候,要确保用括号给?操作符一个合适的范围。例如,声明可选整数数组,应该写成(Int[])?;写成Int[]?会报错。
当你声明一个可选变量或者可选属性的时候没有提供初始值,它的值会默认为nil。
C 和 Objective-C 中并没有可选类型这个概念。最接近的是 Objective-C 中的一个特性,一个方法要不返回一个对象要不返回 nil , nil 表示“缺少一个合法的对象”。然而,这只对对象起作用——对于结构体,基本的C 类型或者枚举类型不起作用。对于这些类型,Objective-C 方法一般会返回一个特殊值(比如 NSNotFound )来暗示值缺失。这种方法假设方法的调用者知道并记得对特殊值进行判断。然而,Swift 的可选类型可以让你暗示任意类型的值缺失,并不需要一个特殊值。
eg: let possibleNumber = "123" let convertedNumber = Int(possibleNumber) // convertedNumber 被推测为类型 "Int?", 或者类型 "optional Int"(实验:将 possibleNumber 赋值 123、star ,实验 123 的时候打印非 nil 值) print("\(convertedNumber)")
如果你声明一个可选常量或者变量但是没有赋值,它们会自动被设置为 nil : eg: var surveyAnswer: String? // surveyAnswer 被自动设置为 nil print("\(surveyAnswer)")
- ** 注意 **
Swift 的 nil 和 Objective-C 中的 nil 并不一样。在 Objective-C 中, nil 是一个指向不存在对象的指针。在 Swift 中, nil 不是指针——它是一个确定的值,用来表示值缺失。任何类型的可选状态都可以被设置为 nil ,不只是对象类型。
- ** 强制解析** 可选类型类似于Objective-C中指针的nil值,但是nil只对类(class)有用,而可选类型对所有的类型都可用,并且更安全。
- ** 自动解析 ** 你可以在声明可选变量时使用感叹号(!)替换问号(?)。这样可选变量在使用时就不需要再加一个感叹号(!)来获取值,它会自动解析。
- ** 可选绑定 ** 使用可选绑定(optional binding)来判断可选类型 ( someOptional ) 是否包含值,如果包含就把值赋给一个临时常量 ( constantName ) 或者变量。可选绑定可以用在if和while语句中来对可选类型的值进行判断并把值赋给一个常量或者变量。 像下面这样在if语句中写一个可选绑定:
if let constantName = someOptional { statements {if . 或者 white 语句...} }
注意: 在 if 条件语句中使用常量和变量来创建一个可选绑定,仅在 if 语句的句中( body )中才能获取到值。相反,在 guard 语句中使用常量和变量来创建一个可选绑定,仅在 guard 语句外且在语句后才能获取到值。
- ** 隐式解析可选类型**
可选类型暗示了常量或者变量可以“没有值”。可选可以通过 if 语句来判断是否有值,如果有值的 话可以通过可选绑定来解析值。 可选类型暗示了常量或者变量可以“没有值”。可选可以通过 if 语句来判断是否有值,如果有值的 话可以通过可选绑定来解析值。 这种类型的可选状态被定义为隐式解析可选类型(implicitly unwrapped optionals)。把想要用作可选的类型 的后面的问号( String? )改成感叹号( String! )来声明一个隐式解析可选类型。
当可选类型被第一次赋值之后就可以确定之后一直有值的时候,隐式解析可选类型非常有用。隐式解析可选类型 主要被用在 Swift 中类的构造过程中。
一个隐式解析可选类型其实就是一个普通的可选类型,但是可以被当做非可选类型来使用,并不需要每次都使用 解析来获取可选值。
- **注意: ** 如果你在隐式解析可选类型没有值的时候尝试取值,会触发运行时错误。和你在没有值的普通可选类型后面加一 个惊叹号一样。
- ** 断言 **
可选类型可以让你判断值是否存在,你可以在代码中优 地处理值缺失的情况。然而,在某些情况下,如果值缺 失或者值并不满足特定的条件,你的代码可能没办法继续执行。这时,你可以在你的代码中触发一个 断言(asse rtion) 来结束代码运行并通过调试来找到值缺失的原因。
可以使 用断言来保证在运行其他代码之前,某些重要的条件已经被满足。如果不满足,断言在运行的时候有个逻辑判断会返回 false ;如果满足,断言在逻辑判断后返回 true ;只有在 true 的情况下程序才会继续的运行,在 false 的情况下会崩溃掉。
eg: let age = 3 assert(age >= 0 , "一个人的年龄不可能小于0") // 假如,我们把 age的值 改为 - 3 就会报错,编译不能通过( 因为 age < 0 断言会触发 ) // 这里只有 age >= 0 的时候,代码才会继续的执行,否则就会报错,不能执行接下来的代码。
如果不需要断言信息,可以省略,就像这样: assert(age >= 0) 代码使用优化编译的时候,断言将会被禁用. 什么时候使用断言?
当条件可能为假时使用断言,但是最终一定要保证条件为真,这样你的代码才能继续运行。断言的适用情景: 整数类型的下标索引被传入一个自定义下标实现,但是下标索引值可能太小或者太大。
需要给函数传入一个值,但是非法的值可能导致函数不能正常执行。 一个可选值现在是 nil ,但是后面的代码运行需要一个非 nil 值。 断言可能导致你的应用终止运行,所以你应当仔细设计你的代码来让非法条件不会出现。然而,在你的应用发布 之前,有时候非法条件可能出现,这时使用断言可以快速发现问题。
#五、运算符
运算符是一个符号,用于告诉编译器执行一个数学或逻辑运算。
- ** Swift 提供了以下几种运算符:**
算术运算符、比较运算符、 逻辑运算符、位运算符 、赋值运算符、区间运算符、其他运算符。
算术运算符:加、减、乘、除、自增、自减运算 期中自增、自减运算在书写的时候要注意: var A = 10 var B = 20
// ?的 写法会报错的 ,好像 自增、自减运算符 只能使用 += 和 -= : //A ++ //print("A++ = \(A)") //B -- //print("B-- = \(B)")
下面?是正确的写法: A += 1 print("A++ = \(A)") B -= 1 print("B-- = \(B)")
- **比较运算符:** 等于、不小于、大于、小于、大于等于、小于等于。
eg: 变量 A 为 10,变量 B 为 20: 运算符 描述 实例
( == ) 等于 (A == B) 为 false。 ( != ) 不等于 (A != B) 为 true。 ( > ) 大于 (A > B) 为 false。 ( < ) 小于 (A < B) 为 true。 ( >= ) 大于等于 (A >= B) 为 false。 ( <= ) 小于等于 (A <= B) 为 true。
- **位运算符** 就是: 非、或、与 运算 ,与OC语言里 的运算规则是一样的。
- **赋值运算**
= 简单的赋值运算,指定右边操作数赋值给左边的操作数。 C = A + B 将 A + B 的运算结果赋值给 C
+= 相加后再赋值,将左右两边的操作数相加后再赋值给左边的操作数。 C += A 相当于 C = C + A
-= 相减后再赋值,将左右两边的操作数相减后再赋值给左边的操作数。 C -= A 相当于 C = C - A
*= 相乘后再赋值,将左右两边的操作数相乘后再赋值给左边的操作数。 C *= A 相当于 C = C * A
/= 相除后再赋值,将左右两边的操作数相除后再赋值给左边的操作数。 C /= A 相当于 C = C / A
%= 求余后再赋值,将左右两边的操作数求余后再赋值给左边的操作数。 C %= A 相当于 C = C % A
<<= 按位左移后再赋值 C <<= 2 相当于 C = C << 2
.>>= 按位右移后再赋值 C >>= 2 相当于 C = C >> 2
&= 按位与运算后赋值 C &= 2 相当于 C = C & 2
^= 按位异或运算符后再赋值 C ^= 2 相当于 C = C ^ 2
|= 按位或运算后再赋值 C |= 2 相当于 C = C | 2
- **区间运算符**
wift 提供了两个区间的运算符。
闭区间运算符:
闭区间运算符(a...b)定义一个包含从a到b(包括a和b)的所有值的区间,b必须大于等于a。 闭区间运算符在迭代一个区间的所有值时是非常有用的,如在for-in循环中: 1...5 区间值为 1, 2, 3, 4 和 5
半开区间运算符:
半开区间(a.. 1..< 5 区间值为 1, 2, 3, 和 4
eg: print("闭区间运算符") for index in 1...5 {
print("\(index)*5 =\(index*5)") }
for index in 1...1000 {
print("\(index)*4 = \(index*4)") }
print("半开闭区间运算符") for index in 1..<5 {
print("\(index)*5 = \(index*5)") }
- ** 其他运算符 ** Swift 提供了其他类型的的运算符,如一元、二元和三元运算符。
一元运算符对单一操作对象操作(如-a)。一元运算符分前置运算符和后置运算符,前置运算符需紧跟在操作对象之前(如!b),后置运算符需紧跟在操作对象之后(如i++)。
一元负号符( - )写在操作数之前,中间没有空格。
二元运算符操作两个操作对象(如2 + 3),是中置的,因为它们出现在两个操作对象之间。
三元运算符操作三个操作对象,和 C 语言一样,Swift 只有一个三元运算符,就是三目运算符(a ? b : c)。
运算符 描述 实例 一元减 数字前添加 - 号前缀 -3 或 -4 一元加 数字前添加 + 号前缀 +6 结果为 6
![运算符优先级.png](//upload-images.jianshu.io/upload_images/755664-2d310d1d3ee3bef8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
- ** 空和运算符 **
空合运算符( a ?? b )将对可选类型 a 进行空判断,如果 a 包含一个值就进行解封,否则就返回一个默认值 b 。表达式 a 必须是 Optional 类型。默认值 b 的类型必须要和 a 存储值的类型保持一致。
空合运算符是对以下代码的简短表达方法: a != nil ? a! : b
上述代码使用了三目运算符。当可选类型 a 的值不为空时,进行强制解封(a!),访问 a 中的值;反之返 回默认值 b 。无疑空合运算符( ?? )提供了一种更为优 的方式去封装条件判断和解封两种行为,显得简洁以 及更具可读性。
注意: 如果 a 为非空值( non-nil ),那么值 b 将不会被计算。这也就是所谓的短路求值。
eg: let defaultColor = "red" var userDefaultColor: String? // 默认值为空 nil var colorNameToUser = userDefaultColor ?? defaultColor print("\(colorNameToUser)")// 打印为 red userDefaultColor = "blue" var colorNameToUser_2 = userDefaultColor ?? defaultColor print("\(colorNameToUser_2)") // 有值就强制解封 可选类型 userDefaultColor 的值。
#六、字符串和字符
- ** 字符串**
Swift 字符串是一系列字符的集合。例如 "Hello, World!" 这样的有序的字符类型的值的集合,它的数据类型为 String。 一个 String 的内容可以用许多方式读取,包括作为一个 Character 值的 合。
- ** 创建字符串 <使用字符串字面量> **
var stringA = "hello world" print(stringA)
// 字符串 实例化 (stringB 使用了类型标注、是一个非可选类型的强制解析的写法) var stringB:String! = "hello world" print(stringB)
// 空字符串 let stringC = String() if stringC.isEmpty {
print("strngC 是空的") }else{
print("stringC 不是空的") }
- ** 字符串拼接 **
你可以将一个字符串赋值给一个变量或常量,变量是可修改的,常量是不可修改的。
// 字符串的拼接使用 + 号
var stringD = "字符串常量" stringD += stringB print(stringD)
- ** 字符串插入值 ** var varA = 20 let letA = 100 var carC:Float = 20.0
var stringResult = "\(varA)*\(letA) = \(varA*letA)" print(stringResult)
- ** 字符串长度计算 ** / 字符串的长度,字符串的长度可以用 string.characters.count 来计算 var varLength = "http://www.baidu.com" let length = varLength.characters.count print("\(varLength)"+"的长度是"+"\(length)")
- ** 字符串比较(是否相等)**
// 字符串的比较 var comA = "swift" var comB = "swift" var comC = "swift!"
if comA == comB {
print("\(comA)"+"与"+"\(comB)"+"是相等的") }else{
print("\(comA)"+"与"+"\(comB)"+"不是相等的") }
- ** Unicode 字符串 ** Unicode 是一个国际标准,用于文本的编码,Swift 的 String 类型是基于 Unicode建立的。你可以循环迭代出字符串中 UTF-8 与 UTF-16 的编码。 UTF-8 、UTF-16 的区别? http://blog.csdn.net/lcj200813138020/article/details/46914153
- ** 字符串函数及运算符 **
isEmpty 判断字符串是否为空,返回布尔值
hasPrefix(prefix: String) 检查字符串是否拥有特定前缀
hasSuffix(suffix: String) 检查字符串是否拥有特定后缀。
Int(String) 转换字符串数字为整型。 实例: eg: let myString: String = "256" let myInt: Int? = Int(myString)
String.characters.count 计算字符串的长度
utf8 您可以通过遍历 String 的 utf8 属性来访问它的 UTF-8 编码
utf16 您可以通过遍历 String 的 utf8 属性来访问它的 UTF-16 编码
unicodeScalars 您可以通过遍历String值的unicodeScalars属性来访问它的 Unicode 标量编码.
+ 连接两个字符串,并返回一个新的字符串
+= 连接操作符两边的字符串并将新字符串赋值给左边的操作符变量
== 判断两个字符串是否相等
< 比较两个字符串,对两个字符串的字母逐一比较。
!= 比较两个字符串是否不相等。
eg: var emptyString = "" // 空字符串 var stillEmpty = String() // 另一种空字符串的形式 let helloWorld = "Hello World!" // 字符串字面量 let a = String(true) // 由布尔值转换为:"true" let b: Character = "A" // 显式创建一个字符类型 let c = String(b) // 从字符 "A" 转换 let d = String(3.14) // 从 Double 类型转换为 "3.14" let e = String(1000) // 从 Int 类型转换为 "1000" let f = "Result = \(d)" // 字符串插值 "Result = 3.14" let g = "\u{2126}" // Unicode 字符,欧米伽符号 Ω
//字符串可以通过传递一个值类型为 Character 的数组作为自变量来初始化: let catCharacters: [Character] = ["C", "a", "t", "!", "?"] let catString = String(catCharacters) print(catString) // 打印输出:"Cat!?"
字符串字面量的特殊字符 字符串字面量可以包含以下特殊字符: • 转义字符 \0 (空字符)、 \\ (反斜线)、 \t (水平制表符)、 \n (换行符)、 \r (回车符)、 \" (双引 号)、 \' (单引号)。 • Unicode 标量,写成 \u{n} (u为小写),其中 n 为任意一到八位十六进制数且可用的 Unicode 位码。
- ** 字符串的插入和删除 **
调用 insert(_:at:) 方法可以在一个字符串的指定索引插入一个字符,调用 insert(contentsOf:at:) 方法可 以在一个字符串的指定索引插入一个段字符串。
调用 remove(at:) 方法可以在一个字符串的指定索引删除一个字符,调用 removeSubrange(_:) 方法可以在一 个字符串的指定索引删除一个子字符串。
var welcome = "hello njw" welcome.insert("!", at: welcome.endIndex) print(welcome)
welcome.remove(at: welcome.startIndex) print(welcome)
// 移除最后一个字母前面的一个字母(是一个字母) welcome.remove(at: welcome.index(before: welcome.endIndex)) print(welcome)
// 移除规定范围内的字符串 (注意:..< 与前面后面的表达式之间要保持一个空格,语法需要) let range = welcome.index(welcome.endIndex, offsetBy: -2) ..< welcome.endIndex welcome.removeSubrange(range) print(welcome)
#七、集合
Swift 提供了三种集合类型的数据用来存储集合数据。他们是数组(Arrays)是有序数据的 。 合(Sets)是无序无重复数据的 。字典(Dictionaries)是无序的键值对的 。 Swift 的 Arrays 、 Sets 和 Dictionaries 类型被实现为泛型集合。
Swift 语言中的 Arrays 、 Sets 和 Dictionaries 中存储的数据值类型必须明确。这意味着我们不能把不正确的数据类型插入其中。同时这也说明我们完全可以对取回值的类型非常自信。
- ** 数组 **
Swift 数组使用有序列表存储同一类型的多个值。相同的值可以多次出现在一个数组的不同位置中。
Swift 数组会强制检测元素的类型,如果类型不同则会报错,Swift 数组应该遵循像Array<Element>这样的形式,其中Element是这个数组中唯一允许存在的数据类型。
如果创建一个数组,并赋值给一个变量,则创建的集合就是可以修改的。这意味着在创建数组后,可以通过添加、删除、修改的方式改变数组里的项目。如果将一个数组赋值给常量,数组就不可更改,并且数组的大小和内容都不可以修改。
NSArray创建静态数组和NSMutableArray创建动态数组。
创建数组 我们可以使用构造语法来创建一个由特定数据类型构成的空数组:
var someArray =[ [SomeType]] ()
以下是创建一个初始化大小数组的语法:
var someArray =[ [SomeType]] (repeating: InitialValue, count: countNum)
Swift 中的 Array 类型还提供一个可以创建特定大小并且所有数据都被默认的构造方法。我们可以把准备加入新数组的数据项数量( count )和适当类型的初始值( repeating )传入数组构造函数: var threeDoubles = Array(repeating: 0.0, count: 3)// threeDoubles 是一种 [Double] 数组,等价于 [0.0, 0.0, 0.0]
以下实例创建了一个类型为 Int ,大小为 3,初始值为 0 的空数组:
var someInts = [Int] (repeating: 0, count: 3)
以下实例创建了含有三个元素的数组:
var someInts:[Int] = [10, 20, 30]
// 修改数组 // 创建特地类型的数组 var intAry = [Int] () // 添加元素 intAry.append(20) intAry.append(30)
我们可以使用加法操作符(+)来合并两种已存在的相同类型数组。新数组的数据类型会从两个数组的数据类型中推断出来:
下面写法错误,必须是同一种类型的数组才能相加 var newAry = intAry + stringAry
eg: intAry += [40] intAry += [10,20,50] // 修改元素 intAry[0] = 0 intAry[1] = 1000
// 遍历数组 for index in intAry{ print("\(index)") }
在遍历的同时,如果我们要为每个数据项的值展示其索引值,可以使用 String 的 enumerated() 方法来进行数组遍历,方法如下:
for (index,item) in intAry.enumerated(){ print("\(index)的下标对应的值是\(item)") }
var intAry2 = [10,20,70,90,22] // 数组的相加,必须保证数组元素数据类型一致,这里实验 var newAry = intAry + intAry2 for (index,item) in newAry.enumerated() {
print("下标为\(index)的元素是\(item)") }
// count 属性 print("新数组的元素的个数是\(newAry.count)")
// isEmpty 属性 print("新数组的个数是否为0,\(newAry.isEmpty)")
元素的插入、删除
调用数组的 insert(_:at:) 方法来在某个具体索引值之前添加数据项:
类似的我们可以使用 remove(at:) 方法来移除数组中的某一项。这个方法把数组在特定索引值中存储的数据项移除并且返回这个被移除的数据项(我们不需要的时候就可以无视它): 如果我们试着对索引越界的数据进行检索或者设置新值的操作,会引发一个运行期错误。我们可以使用索引值和 数组的 count 属性进行比较来在使用某个索引之前先检验是否有效。除了当 count 等于 0 时(说明这是个空数 组),最大索引值一直是 count - 1 ,因为数组都是零起索引。
newAry.insert(12, at: 0) newAry.insert(99999999, at: 6) print(newAry)
// 移除索引为2的数据项 newAry.remove(at: 2) print(newAry)
// 数组的遍历 使用 for-in 循环来遍历所有数组中的数据项:
for oneIntNumber in newAry {
// 插入了格式化的换行符 print("\n " + "\(oneIntNumber)") }
- ** 集合 **
合(Set)用来存储相同类型并且没有确定顺序的值。当 合元素顺序不重要时或者希望确保每个元素只出现一次 时可以使用 合而不是数组。 Swift的 Set 类型被桥接到 Foundation 中的 NSSet 类。 集合的语法: Swift 中的 Set 类型被写为 Set<Element> ,这里的 Element 表示 Set 中允许存储的类型,和数组不同的是, 合没有等价的简化形式。
创建一个空的集合
1、 通过构造器语法创建 集合 var letters = Set<Character>() //通过构造器,这里的 letters 变量的类型被推断为 Set<Character> 。 print("letters is of type Set<Character> with \(letters.count) items.")
letters.insert("a") letters 现在含有1个 Character 类型的值 letters = [] letters 现在是一个空的 Set, 但是它依然是 Set<Character> 类型
2、用数组字面量创建 集合
你可以使用数组字面量来构造集合,并且可以使用简化形式写一个或者多个值作为集合元素。 一个 Set 类型不能从数组字面量中被单独推断出来,因此 Set 类型必须显式声明。然而,由于 Swift 的类型推 断功能,如果你想使用一个数组字面量构造一个 Set 并且该数组字面量中的所有元素类型相同,那么你无须写出Set 的具体类型。 下面的例子创建一个称之为 favoriteGenres 的 合来存储 String 类型的值: var favoriteGenres: Set<String> = ["Rock", "Classical", "Hip hop"] // favoriteGenres 被构造成含有三个初始值的 合 上面的写法还可以按照及简单的形式去写 var favorite:Set = ["Rock", "Classical", "Hip hop"] // 数组字面量中的所有元素类型相同,如果不同则不能这样写
访问和修改一个 集合 集合 的个数属性 count print("I have \(favoriteGenres.count) favorite music genres.") // 打印 "I have 3 favorite music genres." 使用布尔属性 isEmpty 作为一个缩写形式去检查 count 属性是否为 0 : if favoriteGenres.isEmpty { print("As far as music goes, I'm not picky.") } else { print("I have particular music preferences.") } 打印 "I have particular music preferences."
为集合 添加一个元素 使用 insert 方法 favoriteGenres.insert("Jack") print(favoriteGenres)
通过调用 Set 的 remove(_:) 方法去删除一个元素,如果该值是该 Set 的一个元素则删除该元素并且返回 被删除的元素值,否则如果该 Set 不包含该值,则返回 nil 。另外, Set 中的所有元素可以通过它的 removeAll() 方法删除。
if let removeGender = favoriteGenres.remove("Jack") { print("\(removeGender)? I'm over it.") }else { print("I never much cared for that.") }
使用 contains(_:) 方法去检查 Set 中是否包含一个特定的值: if favoriteGenres.contains("Classical") { print("我在集合里发现了 Classical") }else { print("在集合里我没有发现 Classical") }
遍历一个集合 你可以在一个 for-in 循环中遍历一个 Set 中的所有值。 for (index,value) in favoriteGenres.enumerated() {
print("第 \(index) 个元素是 \(value)") }
print("\n 没有排序前的集合元素数据遍历 \n") for gender in favoriteGenres { print(gender) }
Swift 的 Set 类型没有确定的顺序,为了按照特定顺序来遍历一个 Set 中的值可以使用 sorted() 方法,它将返回一个有序数组,这个数组的元素排列顺序由操作符'<'对元素进行比较的结果来确定. print("\n 排序之后的集合元素数据遍历 \n") for gender in favoriteGenres.sorted() {
print(gender) }
集合 的操作 我们能够将两个集合合并到一起,判断两个集合的公共元素,或者判断两个集合的是否全部包含,部分包含,或者不相交。 求两个集合的交集 (使用 intersection(_:) 方法根据两个集合中都包含的值创建的一个新的集合。) 求两个集合的补集 使用 symmetricDifference(_:) 方法根据在一个集合中但不在两个集合中的值创建一个新的集合。 使用 union(_:) 方法根据两个集合的值创建一个新的集合。 使用 subtracting(_:) 方法根据不在该集合中的值创建一个新的集合。 使用“是否相等”运算符( == )来判断两个集合是否包含全部相同的值。 使用 isSubset(of:) 方法来判断一个集合中的值是否也被包含在另外一个集合中。 使用 isSuperset(of:) 方法来判断一个集合中包含另一个集合中所有的值。 使用 isStrictSubset(of:) 或者 isStrictSuperset(of:) 方法来判断一个集合是否是另外一个集合的子集合或 者父集合并且两个合并不相等。 使用 isDisjoint(with:) 方法来判断两个集合是否不含有相同的值(是否没有交集 )。
let oddDigits: Set = [100, 3, 5, 7, 9] let evenDigits: Set = [0, 2, 4, 6, 8] let singleDigitPrimeNumbers: Set = [2, 3, 5, 7]
print("\n") print(oddDigits.intersection(evenDigits).sorted())// 求交集 print("\n oddDigits = \(oddDigits); singleDigitPrimeNumbers = \(singleDigitPrimeNumbers)") print(oddDigits.symmetricDifference(singleDigitPrimeNumbers).sorted()) print("\n") print(oddDigits.union(evenDigits).sorted())// 求并集 print("\n") print(evenDigits.subtracting(singleDigitPrimeNumbers).sorted())
let houseAnimals: Set = ["?", "?"] let farmAnimals: Set = ["?", "?", "?", "?", "?"] let cityAnimals: Set = ["?", "?"]
houseAnimals.isSubset(of: farmAnimals) print(houseAnimals.isSubset(of: farmAnimals)) // true
farmAnimals.isSuperset(of: houseAnimals) print(farmAnimals.isSuperset(of: houseAnimals)) // true
farmAnimals.isDisjoint(with: cityAnimals) print(farmAnimals.isDisjoint(with: cityAnimals)) // true
- ** 字典 **
Swift 字典用来存储无序的相同类型数据的集合,Swift 字典会强制检测元素的类型,如果类型不同则会报错。
Swift 字典每个值(value)都关联唯一的键(key),键作为字典中的这个值数据的标识符。
和数组中的数据项不同,字典中的数据项并没有具体顺序。我们在需要通过标识符(键)访问数据的时候使用字典,这种方法很大程度上和我们在现实世界中使用字典查字义的方法一样。
Swift 字典的key没有类型限制可以是整型或字符串,但必须是唯一的。
如果创建一个字典,并赋值给一个变量,则创建的字典就是可以修改的。这意味着在创建字典后,可以通过添加、删除、修改的方式改变字典里的项目。如果将一个字典赋值给常量,字典就不可修改,并且字典的大小和内容都不可以修改。
创建字典 我们可以使用以下语法来创建一个特定类型的空字典:
var someDict = [KeyType: ValueType] ()
以下是创建一个空字典,键的类型为 Int,值的类型为 String 的简单语法:
var someDict = [Int: String] ()
以下为创建一个字典的实例:
var someDict:[Int:String] = [1:"One", 2:"Two", 3:"Three"] 们在用字典字面量构造字典时,如果它的键和值都有各自一致的类型,那么就不必写出字典的类 型。
// 创建一个 特定类型 的空字典 var firstDic = [String:String] () var intStringDic = [Int:String] ()
// 创建一个特定类型字典,并实例化该字典 intStringDic = [1:"one",2:"two",3:"three",4:"four",]
var intStrDic:[Int:String] = [1:"one",2:"two",3:"three",4:"four"]// 使用字典字面量去创建一个字典
// 访问字典 var someVar = intStringDic[1] print("someVar = \(someVar)")
修改字典 <updateValue(forKey:)> 使用 updateValue(forKey:) 增加或更新字典的内容。如果 key 不存在,则添加值,如果存在则修改 key 对应的值。updateValue(_:forKey:)方法返回Optional值。实例如下:
var oldVar = intStringDic.updateValue("one 新值", forKey: 1) print("新的字典是\(intStringDic)")
// 修改字典 <通过指定的 key 来修改> intStringDic[0] = "修改了哈?" print("新的字典是\(intStringDic)")
// 移除 键值对 (key-value) var removeDic = intStringDic.removeValue(forKey: 1) print("新的字典是\(intStringDic)")
// 对字典的遍历 <for in 遍历> for (key,value) in intStringDic{
print("字典 key:\(key)-value:\(value)") }
// 遍历字典 <enumerate> for (key,value) in intStringDic.enumerated(){
print("字典dic 键:\(key)-值:\(value)") }
// 字典转换为数组 let dicKeys = [Int] (intStringDic.keys) let dicValues = [String] (intStringDic.values)
print("字典的键是\(dicKeys);字典的值是\(dicValues)")
// count 属性 print("字典含有的键值对是\(intStringDic.count)个")
// isEmpty 属性 var nulDic:[String:String] = [:] // 此时字典变为空字典了 if nulDic.isEmpty {
print("字典是空的") }else{
print("字典不是空的") }
#八、流程控制
Swift提供了多种流程控制结构,包括可以多次执行任务的 while 循环,基于特定条件选择执行不同代码分支的 if 、 guard 和 switch 语句,还有控制流程跳转到其他代码位置的 break 和 continue 语句。Swift 还提供了 for-in 循环,用来更简单地遍历数组(array),字典(dictionary),区间(range),字符串(string)和其他序列类型。
Swift 的 switch 语句比 C 语言中更加强大。在 C 语言中,如果某个 case 不小心漏写了 break ,这个 case 就会贯穿至下一个 case,Swift 无需写 break ,所以不会发生这种贯穿的情况。case 还可以匹配很多不同的模式,包括间隔匹配(interval match),元组(tuple)和转换到特定类型。 switch 语句的 case 中匹配的值可以绑定成临时常量或变量,在case体内使用,也可以用 where 来描述更复杂的匹配条件。
- ** 条件语句 **
Swift 提供了以下几种类型的条件语句:
if 语句 if 语句 由一个布尔表达式和一个或多个执行语句组成。
if...else 语句 if 语句 后可以有可选的 else 语句, else 语句在布尔表达式为 false 时执行。
if...else if...else 语句 if 后可以有可选的 else if...else 语句, else if...else 语句常用于多个条件判断。
内嵌 if 语句 你可以在 if 或 else if 中内嵌 if 或 else if 语句。
switch 语句 switch 语句允许测试一个变量等于多个值时的情况。
当多个条件可以使用同一种方法来处理时,可以将这几种可能放在同一个 case 后面,并且用逗号隔开。当case后 面的任意一种模式匹配的时候,这条分支就会被匹配。并且,如果匹配列表过长,还可以分行书写。如例子3。
- ** 循环语句 **
Swift 语言提供了以下几种循环类型。点击链接查看每个类型的详细描述:
for-in 遍历一个集合里面的所有元素,例如由数字表示的区间、数组中的元素、字符串中的字符。
for 循环 用来重复执行一系列语句直到达成特定条件达成,一般通过在每次循环完成后增加计数器的值来实现。
while 循环 运行一系列语句,如果条件为true,会重复运行,直到条件变为false。
repeat...while 循环 类似 while 语句区别在于判断循环条件之前,先执行一次循环的代码块。如例子1。
- ** 循环控制**
循环控制语句改变你代码的执行顺序,通过它你可以实现代码的跳转。 Swift 以下几种循环控制语句:
continue 语句 告诉一个循环体立刻停止本次循环迭代,重新开始下次循环迭代。
break 语句 中断当前循环。Swift 中的 switch 不会从上一个 case 分支落入到下一个 case 分支中。相反,只要第一个匹配到的 case 分支完成了它需要执行的语句,整个 switch 代码块完成了它的执行。相比之下,C 语言要求你显式地插入 break 语句到每个 case 分支的末尾来阻止自动落入到下一个 case 分支中。Swift 的这种避免默认落入到下一个分支中的特性意味着它的 switch 功能要比 C 语言的更加清晰和可预测,可以避免无意识地执行多个 case 分支从而引发的错误。如例子2.
fallthrough 语句 如果在一个case执行完后,继续执行下面的case,需要使用fallthrough(贯穿)关键字。
reture 语句多用在函数中
throw 语句多用在错误的异常抛出语句中。
eg: var A = 10 if A<20 { print("A小于20") }else{ print("A不小于20") } // for - in 循环 // 遍历一个集合里面的所有元素,例如由数字表示的区间、数组中的元素、字符串中的字符。 // 遍历 集合 var someInts:[Int] = [10,20,30,40,50,60] for index in someInts { print("index的值是 \(index)") } // 遍历 数字标示的区间 for index in 1...5{ print("index = \(index)") }
- ** 例子?** 【例子1】、 repeat while 语句的例子:
let finalSquare = 25
var square = 0 var diceRoll = 0
repeat { // 顺着 梯@@子 爬上去或者顺着蛇滑下去 square += board[square] // 掷骰子 diceRoll += 1 if diceRoll == 7 { diceRoll = 1 } // 根据点数移动 square += diceRoll } while square < finalSquare print("Game over!")
【 例子2】、 贯穿语句的例子 (fallthrough):
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) // 输出 "The number 5 is a prime number, and also an integer."
【例子3】、switch 语句的复合匹配:
let someCharacter: Character = "e" switch someCharacter { case "a", "e", "i", "o", "u": print("\(someCharacter) is a vowel") case "b", "c", "d", "f", "g", "h", "j", "k", "l", "m", "n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z": print("\(someCharacter) is a consonant") default: print("\(someCharacter) is not a vowel or a consonant") } // 输出 "e is a vowel"
【例子4】、带标签的语句
let finalSquare = 25 var board = [Int] (repeating: 0, count: finalSquare + 1) board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02 board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08 var square = 0 var diceRoll = 0
gameLoop: while square != finalSquare { diceRoll += 1 if diceRoll == 7 { diceRoll = 1 } switch square + diceRoll { case finalSquare: // 骰子数刚好使玩家移动到最终的方格里,游戏结束。 break gameLoop case let newSquare where newSquare > finalSquare: // 骰子数将会使玩家的移动超出最后的方格,那么这种移动是不合法的,玩家需要重新掷骰子 continue gameLoop default: // 合法移动,做正常的处理 square += diceRoll square += board[square] } } print("Game over!")
- ** 提前退出 guard 的 使用** 像 if 语句一样, guard 的执行取决于一个表达式的布尔值。我们可以使用 guard 语句来要求条件必须为真 时,以执行 guard 语句后的代码。不同于 if 语句,一个 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(person: ["name": "John"]) // 输出 "Hello John!" // 输出 "I hope the weather is nice near you." greet(person: ["name": "Jane", "location": "Cupertino"]) // 输出 "Hello Jane!" // 输出 "I hope the weather is nice in Cupertino."
- ** 检测 API 的可用性 **
Swift内置支持检查 API 可用性,这可以确保我们不会在当前部署机器上,不小心地使用了不可用的API。 编译器使用 SDK 中的可用信息来验证我们的代码中使用的所有 API 在项目指定的部署目标上是否可用。如果我 们尝试使用一个不可用的 API,Swift 会在编译时报错。 我们在 if 或 guard 语句中使用 可用性条件(availability condition) 去有条件的执行一段代码,来在运行时判 断调用的API是否可用。编译器使用从可用性条件语句中获取的信息去验证,在这个代码块中调用的 API 是否可 用。
if #available(iOS 10, macOS 10.12, *) { // 在 iOS 使用 iOS 10 的 API, 在 macOS 使用 macOS 10.12 的 API print("在 iOS 使用 iOS 10 的 API, 在 macOS 使用 macOS 10.12 的 API") } else { // 使用先前版本的 iOS 和 macOS 的 API print("使用先前版本的 iOS 和 macOS 的 API") }
以上可用性条件指定,在iOS中, if 语句的代码块仅仅在 iOS 10 及更高的系统下运行;在 macOS中,仅在 macO S 10.12 及更高才会运行。最后一个参数, * ,是必须的,用于指定在所有其它平台中,如果版本号高于你的设 备指定的最低版本,if语句的代码块将会运行。
#九、函数
Swift 定义函数使用关键字 func。
定义函数的时候,可以指定一个或多个输入参数和一个返回值类型。
每个函数都有一个函数名来描述它的功能。通过函数名以及对应类型的参数值来调用这个函数。函数的参数传递的顺序必须与参数列表相同。
在 Swift 中,每个函数都有一个由函数的参数值类型和返回值类型组成的类型。你可以把函数类型当做任何其他普通变量类型一样处理,这样就可以更简单地把函数当做别的函数的参数,也可以从其他函数中返回函数。函数的定义可以写在其他函数定义中,这样可以在嵌套函数范围内实现功能封装。
函数的实参传递的顺序必须与形参列表相同, 后定义函数的返回值类型。
语法如下: func funcname(形参) -> returntype { Statement1 Statement2 …… Statement N return parameters }
eg: 定义一个 入参、出参 都为 String 的 stringDealAction 函数
func stringDealAction(str:String) -> String return str.appending("+SWIFT") }
- ** 函数的参数与返回值 **
函数参数与返回值在 Swift 中非常的灵活。你可以定义任何类型的函数,包括从只带一个未名参数的简单函数到 复杂的带有表达性参数名和不同参数选项的复杂函数。
1、无参函数 eg: 函数可以没有参数。下面这个函数就是一个无参数函数,当被调用时,它返回固定的 String 消息: func sayHelloWorld() -> String { return "hello, world" } print(sayHelloWorld()) 打印 "hello, world" 尽管这个函数没有参数,但是定义中在函数名后还是需要一对圆括号。当被调用时,也需要在函数名后写一对括号。 无返回值函数:严格上来说,虽然没有返回值被定义,greet(person:) 函数依然返回了值。没有定义返回类型的函数会返回一 个特殊的 Void 值。它其实是一个空的元组(tuple),没有任何元素,可以写成()。 func sayGoodMornig() { print("Good Morning njw") } sayGoodMornig()
2、函数的调用: 我们可以通过函数名以及对应类型的参数值来调用函数,函数的参数传递的顺序必须与参数列表相同。
3、元组 作为函数参数使用: 函数可以接受一个或者多个参数,我们也可以使用元组(tuple)向函数传递一个或多个参数: func mult(num1:Int,num2:Int)->Int{ return num1*num2 } print("2*3 =" + " (\(mult(num1: 2, num2: 3)))")
4、元组 作为函数的返回值: 函数返回值类型可以是字符串,整型,浮点型等。 元组与数组类似,不同的是,元组中的元素可以是任意类型,使用的是圆括号。 你可以用元组(tuple)类型让多个值作为一个复合值从函数中返回。 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) }
print("[10,20,30,40,50]找到最大的数值与最小的数值分别是"+"(\(minMax(array: [10,20,30,40,50])))") minMax(_:)函数返回一个包含两个Int值的元组,这些值被标记为min和max,以便查询函数的返回值时可以通过名字访问它们。 如果你不确定返回的元组一定不为nil,那么你可以返回一个可选的元组类型。
你可以通过在元组类型的右括号后放置一个问号来定义一个可选元组,例如(Int, Int)?或(String, Int, Bool)?
注意 可选元组类型如(Int, Int)?与元组包含可选类型如(Int?, Int?)是不同的.可选的元组类型,整个元组是可选的,而不只是元组中的每个元素值。 前面的minMax(_:)函数返回了一个包含两个Int值的元组。但是函数不会对传入的数组执行任何安全检查,如果array参数是一个空数组,如上定义的minMax(_:)在试图访问array[0]时会触发一个运行时错误。
为了安全地处理这个"空数组"问题,将minMax(_:)函数改写为使用可选元组返回类型,并且当数组为空时返回nil: func minMax(array:[Int])->(min:Int,max:Int)?
5、函数参数名称
函数都有一个外部参数和一个局部参数名。 局部参数就是:只能在函数的内部使用; 外部参数是:你可以在局部参数名前指定外部参数名,中间以空格分隔,外部参数名用于在函数调用时传递给函数的参数。
###### 函数参数——(外部参数) 如果你提供了外部参数名,那么函数在被调用时,必须使用外部参数名。
> func outParameterAction(firstNum a:Int, secondNum b:Int){ > if a > b { > print("最大数是 \(a)") > }else{ > print("最小数是 \(a)") } }
通过指定参数标签的方法,我们可以增强一个函数的可读性,让其更加的接近自然语言。
eg: ###### 指定参数标签 // 你可以在函数名称前指定它的参数标签,中间以空格分隔:
> func someFunction(argumentLabel parameterName: Int) { // 在函数体内,parameterName 代表参数值 } //这个版本的 greet(person:) 函数,接收一个人的名字和他的家乡,并且返回一句问候: func greet(person: String, from hometown: String) -> String { return "Hello \(person)! Glad you could visit from \(hometown)." } print(greet(person: "Bill", from: "Cupertino")) // 打印 "Hello Bill! Glad you could visit from Cupertino." //参数标签的使用能够让一个函数在调用时更有表达力,更类似自然语言,并且仍保持了函数内部的可读性以及清晰的意图。
###### 忽略参数标签: 如果你不希望为某个参数添加一个标签,可以使用一个下划线( _ )来代替一个明确的参数标签。 eg: >func someFunction(_ firstParameterName: Int, secondParameterName: Int) { // 在函数体内,firstParameterName 和 secondParameterName 代表参数中的第一个和第二个参数值 } someFunction(1, secondParameterName: 2) //如果一个参数有一个标签,那么在调用的时候必须使用标签来标记这个参数。
###### 默认参数值:
你可以在函数体中通过给参数赋值来为任意一个参数定义默认值(Deafult Value)。当默认值被定义后,调用这 个函数时可以忽略这个参数。
func someFunction(parameterWithoutDefault: Int, parameterWithDefault: Int = 12) { // 如果你在调用时候不传第二个参数,parameterWithDefault 会值为 12 传入到函数体中。 } someFunction(parameterWithoutDefault: 3, parameterWithDefault: 6) // parameterWithDefault = 6 someFunction(parameterWithoutDefault: 4) // parameterWithDefault = 12
###### 可变参数:
可变参数可以接受零个或多个值。函数调用时,你可以用可变参数来指定函数参数,其数量是不确定的。
可变参数通过在变量类型名后面加入(...)的方式来定义。
eg: >func vari<Y>(members:Y...){ for i in members { print(i) } } vari(members: 1,2,3,4,5,6) vari(members: 1.23,2.23,3.23,4.23,5.23) vari(members: "guge","baodu","damuzhi")
可变参数的传入值在函数体中变为此类型的一个数组。 注意:一个函数最多只能拥有一个可变参数。 eg: >例如,一个叫做 numbers 的 Double... 型可变参 数,在函数体内可以当做一个叫 numbers 的 [Double] 型的数组常量。 下面的这个函数用来计算一组任意长度数字的 算术平均数(arithmetic mean): 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) // 返回 3.0, 是这 5 个数的平均数。 arithmeticMean(3, 8.25, 18.75) // 返回 10.0, 是这 3 个数的平均数。
###### 输入、输出参数 ( 能在函数内部去修改外部的值 )
函数参数默认是常量。试图在函数体中更改参数值将会导致编译错误(compile-time error)。这意味着你不能错 误地更改参数值。如果你想要一个函数可以修改参数的值,并且想要在这些修改在函数调用结束后仍然存在,那 么就应该把这个参数定义为输入输出参数(In-Out Parameters)。 定义一个输入输出参数时,在参数定义前加 inout 关键字。一个输入输出参数有传入函数的值,这个值被函数 修改,然后被传出函数,替换原来的值。
注意 输入输出参数不能有默认值,而且可变参数不能用 inout 标记。
你只能传递变量给输入输出参数。你不能传入常量或者字面量,因为这些量是不能被修改的。当传入的参数作为 输入输出参数时,需要在参数名前加 & 符,表示这个值可以被函数修改。
// eg:下例中, 函数有两个分别叫做 和 的输入输出参数:
> |
请发表评论