Swift学习笔记五
基础运算符
Swift的大部分运算符和C及OC相同,也分一元二元多元的,这里只记录一些Swift特有的性质或写法。
赋值运算符( = )
在等号右边是一个有多个值的元组时,它的成员值可以分解并同时分别赋值给常量或者变量:
let (x, y) = (1, 2) // x is equal to 1, and y is equal to 2
和C、OC不同的是,赋值运算符本身并不返回值,因此如下写法是错误的:
if x = y { // this is not valid, because x = y does not return a value }
这主要是为了防止其和相等运算符混淆。
取余运算符(%)
取余运算在有些语言中也被称为取模,不过在Swift中不能这样称,因为负数的时候,余数也是带符号的,比如 -9 % 4 = -1,并且,第二个操作数的符号是被忽略的,也就是说,
a % b 和 a % -b总是返回相同的值。
与C和OC中的取余运算符不同,Swift中的取余也可以用于浮点数:8 % 2.5 = 0.5
复合赋值运算符
比如a+=2意味着a=a+2,不过复合赋值运算符本身并不返回值,因此let b = a += 2 是错误的。
Nil合并运算符
nil合并运算符(a ?? b)在可选项a有值的时候展开a,如果a没有值,就返回b的值。a必须是一个optional值,并且b和a存储的值应该是统一类型。它的意思就是
(a != nil) ? a! : b //这里第二个!是用来强制展开optional值的
nil合并运算符是一种优雅的写法,可读性也更高,并且,如果a有值,那么b将不会参与运算。
范围运算符
Swift有两个范围运算符,"..."和"..<",a...b表示从a到b并且包含a和b的范围,a..<b表示从a到b但不包含b的范围,此时如果a=b,则范围为空,当然,这两个都要求a不能大于b。
字符串和字符
Swift的字符串和字符语法很简单,也可以直接用+号连接多个字符串,并且Swift的字符串提供一种快速、符合Unicode编码的文本处理工具。
并且,字符串中可以插入常量、变量、字面量、表达式。
Swift的string类型和Foundation框架中的NSString是相同的,如果是基于Cocoa的Foundation框架开发,那么所有NSString的API都可以用在Swift的String上。
字符串字面量
字符串字面量是指用双引号包围起来的定义好的字符序列。比如:let someString = "Some string literal value”。此时编译器会降someString的类型设定为String,因为它是用一个字符串字面量被初始化的。
字符串字面量可以包含一些特殊转义符号:
\0 (null), \\ (反斜杠), \t (水平tab), \n (换行符), \r (回车), \" (双引号) and \' (单引号)
也可以包含直接的Unicode纯量字符(Unicode scalar),Unicode scalar是指在某个指定范围内的任意Unicode代码点,它代表一个Unicode字符。在字符串中包含Unicode scalar时,用u开头,加上大括号包围的代码点数字。
let wiseWords = "\"Imagination is more important than knowledge\" - Einstein" // "Imagination is more important than knowledge" - Einstein let dollarSign = "\u{24}" // $, Unicode scalar U+0024 let blackHeart = "\u{2665}" // ♥, Unicode scalar U+2665 let sparklingHeart = "\u{1F496}" // 💖, Unicode scalar U+1F496
创建字符串,可以用字符串字面量创建,也可以用初始化方法:String() 。
与OC不同的是,Swift中的字符串如果是被赋给变量,那么它是可以被修改的。OC中,需要选择NSString和NSMutableString两个类来确定该字符串是否能被修改。
Swift中String是值类型(value type)的,值类型是指当它被赋给常量或者变量,或者被传递给函数的时候,它的值会被拷贝出来进行赋予和传递操作,而不是原始的那个。这一点和OC是不一样的,在OC中,你创建一个NSString的实例,那么你在赋值和传递的时候,都是用的一个指向该NSString的引用。没有发生拷贝操作。
Swift之所以要这样改变,是为了减少开发者难度,比如,当你的方法接收到某个String的时候,你可以确信这个String就是完全被你控制的,不用担心别的地方会修改它,因为它不是引用,而是拷贝出来的值。不过编译器其实并不是每次都拷贝了值的,它只是在需要的时候做了这个操作,这样可以减少很多性能开支。
字符
字符串就是一些列有序排列的字符集合。可以对字符串用for in来遍历其中的字符。
for character in "Dog!🐶" { println(character) } // D // o // g // ! // 🐶
字符串也可以通过一个字符数组来创建:
let catCharacters: [Character] = ["C", "a", "t", "!", "🐱"] let catString = String(catCharacters) println(catString) // prints "Cat!🐱”
注意:不能将字符串或者字符追加(append)到一个已经定义的字符类型变量(Character)后面,因为字符类型是单个字符。
字符串插值(String Interpolation)
Swift的字符串可以混合插入很多其他东西比如常量、变量、表达式、字面量等等,用反斜杠和括号来实现这种插入,这个特性非常实用。
let multiplier = 3 let message = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)" // message is "3 times 2.5 is 7.5”
注意:括号内部的表达式不能包含未转义的双引号、反斜杠,也不能包含回车、换行符。
扩展字元簇(Extended Grapheme Clusters)
Grapheme是指某种自然语言中的最小单元,它并不一定有实际意义,但是它们组合成这种语言的单个字符。Swift语言的每个字符(Character)都是一个独立的扩展字元簇,一个扩展字元簇就是由一个或多个Unicode scalar(Unicode纯量)的有序排列从而组合成可读的字符。
比如:字母é可以是一个单独的Unicode scalar:U+00E9,也可以是多个纯量的组合:U+0065U+0301 (其中U+0065就是字母e)。在Swift中,这两种情况都认为是一个字符,因此获取字符串长度的时候(用全局函数count()),返回的值是相同的,这意味着字符串的改变并不一定意味着其长度发生变化。
注意区分这和OC中NSString的length的区别,NSString的长度是基于字符串在UTF-16编码表示时其中包含的16位的单元的个数,而不是Unicode扩展字元簇的数目。为了反映这个区别,NSString的length属性在Swift中用utf16Count函数来代替。
字符串的API
每个String都有关联的索引类型(index type),它标识字符串中字符所在的位置,用具体的index来获取String中位于该位置的字符。startIndex和endIndex会返回字符串初始和结束位置。
一个String的某个索引类型值可以通过predecessor()或successor()获取与它相邻的前面或后面的索引值。任何索引值都可以通过其他索引值经过一系列操作得到,或者通过全局函数advance(start:n:),尝试获取String范围之外的索引会触发运行时错误。
let greeting = "Guten Tag" // prints "greeting: String = "Guten Tag"" println(greeting.startIndex) // 0 println(greeting.endIndex) // 9 greeting[greeting.startIndex.successor()] // u greeting[greeting.endIndex.predecessor()] // g let index = advance(greeting.startIndex, 7) greeting[index] // a greeting.endIndex.successor() // fatal error: can not increment endIndex
indicies(_:)可以创建一个字符串中所有单个字符的索引范围
for index in indices(greeting) { print("\(greeting[index]) ") } // prints "G u t e n T a g”
insert(_:atIndex:)用于向字符串特定索引位置插入一个字符:
var welcome = "hello" welcome.insert("!", atIndex: welcome.endIndex) println(welcome) // prints "hello!”
splice(_:atIndex:)用于向字符串特定索引位置插入一个字符串:
welcome.splice(" there", atIndex: welcome.endIndex.predecessor()) println(welcome) // prints "hello there!”
removeAtIndex(_:)用于删除字符串特定索引位置的一个字符:
welcome.removeAtIndex(welcome.endIndex.predecessor()) // ! println(welcome) // prints "hello there”
removeRange(_:)用于删除字符串特定范围的子串:
let range = advance(welcome.endIndex, -6)..<welcome.endIndex welcome.removeRange(range) println(welcome) // prints "hello”
字符串比较直接用 ==和 != 。
当字符串的扩展字元簇标准地(canonically)相等时(canonically相等是指扩展字元簇是指它们具备相同的语言意义及外观,而不管它们的Unicode纯量组成),就判断它们相等。
// "Voulez-vous un café?" using LATIN SMALL LETTER E WITH ACUTE let eAcuteQuestion = "Voulez-vous un caf\u{E9}?" // "Voulez-vous un café?" using LATIN SMALL LETTER E and COMBINING ACUTE ACCENT let combinedEAcuteQuestion = "Voulez-vous un caf\u{65}\u{301}?" if eAcuteQuestion == combinedEAcuteQuestion { println("These two strings are considered equal") } // prints "These two strings are considered equal”
hasPrefix(_:)和hasSuffix(_:) 用来判断字符串是否含有特定的前缀或后缀。它们返回布尔值。
字符串的Unicode表示
当把一个Unicode编码的字符串写入一个文本文件或者其他存储区的时候,字符串中的Unicode scalars会以各种基于Unicode的编码格式进行编码。比如UTF-8、UTF-16、UTF-32,可以通过String的属性获取它在不同编码时的表示:
utf8属性获取UTF-8编码格式时的码元集合;
utf16属性获取UTF-16编码格式时的码元集合;
unicodeScalars属性获取UTF-32编码格式时的码元集合;
let dogString = "Dog‼🐶" for codeUnit in dogString.utf8 { print("\(codeUnit) ") } print("\n") // 68 111 103 226 128 188 240 159 144 182 for codeUnit in dogString.utf16 { print("\(codeUnit) ") } print("\n") // 68 111 103 8252 55357 56374 for scalar in dogString.unicodeScalars { print("\(scalar.value) ") } print("\n") // 68 111 103 8252 128054
for scalar in dogString.unicodeScalars {
println("\(scalar) ")
}
// D
// o
// g
// ‼
// 🐶
这篇就到这里,下次开始介绍集合类型。