swift语法基础(二)

基础部分

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

如图所示:下方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