基础部分
swift中包含了C中所有的基础数据类型,Int,Double,Float,Bool,String。还提供了三种基本的集合类型,Array,Set,Dictionary。参考集合类型部分。
在swift中广泛使用值不可变的变量即常量,在swift中,如果你要处理的值不需要改变,那使用常量可使代码更加安全。
swift中还增加了高阶数据类型比如元组(Tuple),元组可以创建或者传递一组数据。作为一组返回值时,可以使用一个元组返回多个值。swift增加了可选类型,可选表示 “那儿有一个值,并且它等于 x ” 或者 “那儿没有值” 。
swift时一门类型安全的语言,这意味着swift可以让你清楚地知道值得类型。
变量和常量
常量和变量必须在使用前声明,使用var声明变量,使用let声明常量。
let maximumNumberOfLoginAttempts = 10
var currentLoginAttempt = 0
可以在一行中声明多个常量或者变量,使用逗号隔开
var x = 0.0, y = 0.0, z = 0.0
类型注解
当声明得常量或者变量时可以加上类型注解,说明要存储得值的类型。格式为:
var welcomeMessage: String
welcomeMessage = "Hello"
可以在一行中定义多个同样类型的变量,使用逗号分隔,在最后一个变量名之后添加类型注解:
var red, green, blue: Double
//一般来说很少使用类型注解,在声明常量或者变量的时候赋给了初值,编译器可以推断出类型。
常量和变量名不能包含数学符号,箭头,保留的Unicode码位,连线与制表符.也不能以数字开头。
输出常量和变量
使用print(_:separator:terminator:) 函数来输出当前常量或变量的值:print是一个用来输出一个或者多个值到适当输出区的全局函数,输出内容到console上,默认情况下,该函数通过添加换行符来结束当前行,如果不想换行,可以传递空字符串给terminator,比如:print(someValue, terminator:””)。
也可以使用 \ ()的方式将字符串进行转义。
注释
swift中的注释和c语言中注释相似, 使用双斜杠。多行注释也相同。
swift并不要求在每条语句结尾处使用分号,也可以添加分号。
整数,整数范围
可以使用不同整数类型的min和max属性来获取对应类型的最小值和最大值
let minValue = UInt8.min // minValue 为 0,是 UInt8 类型
let maxValue = UInt8.max // maxValue 为 255,是 UInt8 类型
Int:在32位平台上与Int32长度相同,在64位平台上与Int64相同
浮点数
浮点数类型比整数类型表示范围更大,Double表示64位浮点数,Float表示32位浮点数。
类型安全和类型推断
Swift 是一个类型安全(type safe)的语言。类型安全的语言可以让你清楚地知道代码要处理的值的类型。如果你的代码需要一个 String,你绝对不可能不小心传进去一个 Int。因此会在编译时进行类型检查。
如果表达式中同时出现了整数和浮点数,会被推断为Double类型:
let anotherPi = 3 + 0.14159
// anotherPi 会被推测为 Double 类型
数值型字面量
一个十进制数,没有前缀
一个二进制数,前缀0b
一个八进制数,前缀0o
一个十六进制数,前缀0x
let decimalInteger = 17
let binaryInteger = 0b10001 // 二进制的17
let octalInteger = 0o21 // 八进制的17
let hexadecimalInteger = 0x11 // 十六进制的17
类型转换
不同类型的变量和常量如果超过范围编译器会报错
let cannotBeNegative: UInt8 = -1
// UInt8 类型不能存储负数,所以会报错
let tooBig: Int8 = Int8.max + 1
// Int8 类型不能存储超过最大值的数,所以会报错
要将一种数字类型转换为另一种。要用当前值来初始化一个期望类型的新数字。如下:
let twoThousand: UInt16 = 2_000
let one: UInt8 = 1
//UInt8和UInt16不能直接计算,需要转换
let twoThousandAndOne = twoThousand + UInt16(one)
SomeType(ofInitialValue)调用swift构造器并传入一个一个初值的默认方法。
整数和浮点数转换
整数和浮点数的转换必须显式指定类型:let three = 3 let pointOneFourOneFiveNine = 0.14159 let pi = Double(three) + pointOneFourOneFiveNine // pi 等于 3.14159,所以被推测为 Double 类型,如果不进行转化无法相加
浮点数到整数
浮点数到整数的转换会阶段小数部分。let pi=3.14159 let integerPi = Int(pi) // integerPi 等于 3,所以被推测为 Int 类型
类型别名
类型别名(type aliases)就是给现有类型定义另一个名字,使用关键字typealias:
typealias AudioSample = UInt16
var maxAmplitudeFound = AudioSample.min
// maxAmplitudeFound 现在是 0
布尔值
Bool值包括true和false。在if判断和控制流作为条件。需要注意的是,当编写条件语句时,如果使用非Bool值则会报错
let i = 1
if i { //i不是布尔值
// 这个例子不会通过编译,会报错
}
let i = 1
if i == 1 { //i==1是布尔值
// 这个例子会编译成功
}
元组
元组是把多个值组成一个复合值。元组内的值可以是任意类型,并不要求是相同类型,如下http状态码:
let http404Error = (404, "Not Found")
// http404Error 的类型是 (Int, String),值是 (404, "Not Found")
元组可以是两个或两个以上类型的组合,比如(Int,Int,Double)。
可以将一个元组的内容分解为单独的常量或者变量,就可以正常使用了。
let (statusCode, statusMessage) = http404Error
print("The status code is \(statusCode)")
// 输出“The status code is 404”
print("The status message is \(statusMessage)")
// 输出“The status message is Not Found”
如果只需要其中一部分元组,分解的时候可以把忽略的部分用下划线(_)标记:
let (justTheStatusCode, _) = http404Error
print("The status code is \(justTheStatusCode)")
// 输出“The status code is 404”
也可以通过下标访问元组中的某个元素,下标从0开始:
print("The status code is \(http404Error.0)")
// 输出“The status code is 404”
print("The status message is \(http404Error.1)")
// 输出“The status message is Not Found”
给元组中的元素命名后,可以通过名字获取元素的值:
let http200Status = (statusCode: 200, description: "OK")
//元组命名
print("The status code is \(http200Status.statusCode)")
// 输出“The status code is 200”
print("The status message is \(http200Status.description)")
// 输出“The status message is OK”
可选类型
使用可选类型来处理值可能缺失的情况,可选类型表示两种可能,可以解析可选类型访问这个值, 或者根本没有值。
let possibleNumber = "123"
let convertedNumber = Int(possibleNumber)
// convertedNumber 被推测为类型 "Int?", 或者类型 "optional Int"
上述String转Int可能失败,因此返回一个可选类型(optional)Int。也即?Int
var serverResponseCode: Int? = 404
// serverResponseCode 包含一个可选的 Int 值 404
serverResponseCode = nil
// serverResponseCode 现在不包含值
//nil不能用于非可选的常量和变量,如果代码中由常量或者变量需要处理值缺失的情况,声明为可选类型。
var surveyAnswer: String?
// surveyAnswer 被自动设置为 nil
if语句以及强制解析
可以使用if语句和nil比较来判断一个可选值是否包含值,使用==或者!=来判断。 如果可选类型有值,不等于nil:
if convertedNumber != nil {
print("convertedNumber contains some integer value.")
}
// 输出“convertedNumber contains some integer value.”
-可选绑定
使用可选绑定来判断可选类型是否包含值,如果包含就赋值给一个临时常量,如下:
if let actualNumber = Int(possibleNumber) {
print("\'\(possibleNumber)\' has an integer value of \(actualNumber)")
} else {
print("\'\(possibleNumber)\' could not be converted to an integer")
}
// 输出“'123' has an integer value of 123”
notice:在if条件句中使用常量或者变量创建一个可选绑定,仅在if条件句的body中有效。
基本运算符
运算符是检查,改变,合并值得特殊符号或者短语。swift支持大部分标准C的运算符,且为了减少常见编码错误进行了部分改进,如:赋值符不再由返回值。算术运算符的结果会被检测并禁止值溢出,以此来避免变量大于或者小于所能表示范围导致的异常。
赋值运算符
let b = 10
var a = 5
a = b
// a 现在等于 10
如果赋值的右边是一个多元组,它的元素可以马上分解成多个常量或者变量:
let (x, y) = (1, 2)
// 现在 x 等于 1,y 等于 2
notice:swift赋值操作不返回任何值,因此
if x = y {
// 此句错误,因为 x = y 并不返回任何值
}
算术运算符
算术运算符除了基本数据类型的运算外,也可用于String的拼接:
"hello, " + "world" // 等于 "hello, world"
比较运算符
所有标准C中的比较运算符都可以在swift中使用。比较运算符多用于if条件语句。
如果两个元组的元素相同且长度相同,就可以进行比较,比较元组大小会按照从左到右,逐值比较的方式,直到两个值不等停止。
//元组比较
(1, "zebra") < (2, "apple") // true,因为 1 小于 2
(3, "apple") < (3, "bird") // true,因为 3 等于 3,但是 apple 小于 bird
(4, "dog") == (4, "dog") // true,因为 4 等于 4,dog 等于 dog
notice:如果元组中包含有Bool类型时不可以进行比较,
("blue", -1) < ("purple", 1) // 正常,比较的结果为 true
("blue", false) < ("purple", true) // 错误,因为 < 不能比较布尔类型
空合运算符(Nil Coalescing Operator)
空合运算符(a??b)将对可选类型a进行空判断,如果a包含一个值就进行解包,否则返回一个默认值b。表达式a必须时Optional类型,默认值b要合a存储值类型一致。
let defaultColorName = "red"
var userDefinedColorName: String? //默认值为 nil
var colorNameToUse = userDefinedColorName ?? defaultColorName
// userDefinedColorName 的值为空,所以 colorNameToUse 的值为 "red"
区间运算符
swift提供了几种方便表达一个区间的区间运算符
闭区间 (a…b) 定义一个从a到b的闭区间
半开区间 (a..<b) 定义一个从a到b但不包括b的区间,
单侧区间 闭区间右另一个表达形式,可以表达往一侧无线延申的区间,
let names = ["Anna", "Alex", "Brian", "Jack"] for name in names[2...] { print(name) } // Brian // Jack for name in names[...2] { print(name) } // Anna // Alex // Brian
半开区间也有单侧表达形式:
for name in names[..<2] { print(name) } // Anna // Alex
逻辑运算符
逻辑运算符与c语言中相同,且&& 和|| 都是左结合的运算符,意味着多元逻辑操作从左开始计算,也可以使用括号标明优先级。
字符和字符串
字符串是一系列字符的集合,swift中使用String类型来表示,String中内容的访问可以使用Character值的集合。
swift中的String和Character类型提供了一种快速且兼容Unicode的方式来处理代码中的文本。
多行字符串字面量
如果需要一个字符串是跨越多行的,使用三个双引号包裹的文本字符集:
let quotation = """
The White Rabbit put on his spectacles. "Where shall I begin,
please your Majesty?" he asked.
"Begin at the beginning," the King said gravely, "and go on
till you come to the end; then stop."
"""
多行字符串在”””包围中。
初始化空字符串
要创建一个空字符串作为初始值,可以将空的字符串字面量赋值给变量,也可以初始化一个String实例
var emptyString = "" // 空字符串字面量
var anotherEmptyString = String() // 初始化方法
// 两个字符串均为空并等价。
通过Bool类型的isEmpty判断字符串是否为空
if emptyString.isEmpty {
print("Nothing to see here")
}
// 打印输出:“Nothing to see here”
字符串可变性
可以通过将一个特定字符串分配给变量对其进行修改,也可以分配一个常量来保证字符串不被修改。
字符串是值类型
在swift中,如果创建一个新的字符串,那么当其进行常量,变量赋值或者在函数中传递时,会进行值拷贝,都会对已有字符串创建新副本,并对该新副本而非原始字符串进行传递或者赋值操作。
下面例子中使用for-in循环打印字符串中每个字符
for character in "Dog!🐶" {
print(character)
}
// D
// o
// g
// !
// 🐶
另外,通过标明一个Character类型并用字符字面量自行赋值,可以建立一个独立的字符常量或者变量。
let exclamationMark: Character = "!"
//创建一个字符
字符串可以通过传递一个Character类型的数组作为自变量来初始化:
let catCharacters: [Character] = ["C", "a", "t", "!", "🐱"]
let catString = String(catCharacters)
print(catString)
// 打印输出:“Cat!🐱”
字符串可以进行连接,这与c语言相同。使用+ ,+=, append进行字符串连接。
Unicode
Unicode是一个用于在不同书写系统中对文本进行编码、表示和处理的国际标准。它使你可以用标准格式表示来自任意语言几乎所有的字符,并能够对文本文件或网页这样的外部资源中的字符进行读写操作。Swift 的 String 和 Character 类型是完全兼容 Unicode 标准的。
计算字符数量
使用count属性获取字符串中Character的个数。可以通过下标来访问和修改字符串。
- 字符串索引 每一个String值都有一个关联的索引类型,String.Index,它对应字符串每个character的位置。不同的字符可能占用不同数量的内存空间,因此不可以使用integer来索引。
使用startIndex获取String的第一个character的索引,使用endIndex获取最后一个character的下一位置索引。(和C++迭代器类似)。如果String是空串,straightIndex和endIndex是相等的。
使用index(before:) 或者index(after:)方法,可以立即得到前面一个或者后面一个索引。 可以调用index(someString:offsetBy:)方法获取对应偏移量的索引。
let greeting = "Guten Tag!"
greeting[greeting.startIndex]
// G
greeting[greeting.index(before: greeting.endIndex)]
// !
greeting[greeting.index(after: greeting.startIndex)]
// u
let index = greeting.index(greeting.startIndex, offsetBy: 7) //获取偏移下标
greeting[index]
// a
获取越界的索引时会报错。
使用indices属性创建一个包含全部索引的范围,用来访问字符串中的单个字符。
for index in greeting.indices { print("\(greeting[index]) ", terminator: "") } // 打印输出“G u t e n T a g ! ”
插入和删除
调用 insert(_:at:)方法可以在一个字符串的指定索引插入一个字符。调用insert(contentsOf:at:)方法可以在一个字符串指定索引插入一个段字符串
var welcome = "hello"
welcome.insert("!", at: welcome.endIndex)
// welcome 变量现在等于 "hello!"
welcome.insert(contentsOf:" there", at: welcome.index(before: welcome.endIndex))
// welcome 变量现在等于 "hello there!"
调用remove(at:)可以在一个字符串的指定索引删除一个字符。调用removerSubrange(_:)可以在一个字符串的指定索引删除一个子字符串
welcome.remove(at: welcome.index(before: welcome.endIndex))
// welcome 现在等于 "hello there"
let range = welcome.index(welcome.endIndex, offsetBy: -6)..<welcome.endIndex
welcome.removeSubrange(range)
// welcome 现在等于 "hello"
- 子字符串
当从字符串中获取一个子串可以使用prefix(_:)方法。就可以得到一个subString实例。 subString中的绝大部分函数和String一样,但是如果需要长时间保存字符串时,使用subString转化为string的方法。
let greeting = "Hello, world!"
let index = greeting.firstIndex(of: ",") ?? greeting.endIndex
let beginning = greeting[..<index]
// beginning 的值为 "Hello"
// 把结果转化为 String 以便长期存储。
let newString = String(beginning)
- String 和subString的区别
subString可以重用原String的内存空间,或者另一个subString的空间。String也有同样优化,但是如果两个String共享内存的话,那么他们相等。
如图所示:下方String是重新申请一块内存存放的。而subString和原来String共享一块内存空间。
比较字符串
swift提供了三种方式比较文本值,字符串字符相等,前缀相等,后缀相等。
字符/字符串相等
可以使用==和!=操作符let quotation = "We're a lot alike, you and I." let sameQuotation = "We're a lot alike, you and I." if quotation == sameQuotation { print("These two strings are considered equal") } // 打印输出“These two strings are considered equal”
前缀/后缀相等
通过调用hasPrefix(:),hasSuffix(:)检查字符串是否拥有特定的前缀和后缀。 两个方法接受一个String参数,返回一个bool值。
字符串的unicode表示
当一个 Unicode 字符串被写进文本文件或者其他储存时,字符串中的 Unicode 标量会用 Unicode 定义的几种 编码格式(encoding forms)编码。每一个字符串中的小块编码都被称 代码单元(code units)。这些包括 UTF-8 编码格式(编码字符串为 8 位的代码单元), UTF-16 编码格式(编码字符串位 16 位的代码单元),以及 UTF-32 编码格式(编码字符串32位的代码单元)。
UTF8,UTF16,UTF32表示参考
https://swiftgg.gitbook.io/swift/swift-jiao-cheng/03_strings_and_characters