fix confilicts
This commit is contained in:
84
source/README.md
Normal file → Executable file
84
source/README.md
Normal file → Executable file
@ -1,12 +1,84 @@
|
||||
# Swift 编程语言
|
||||
> Swift 兴趣交流群:`305014012`,307017261(已满)
|
||||
> [Swift 开发者社区](http://swiftist.org)
|
||||
|
||||
Swift 是苹果在 WWDC 2014 上发布的一款全新的编程语言,本书译自苹果官方的 Swift 教程《The Swift Programming Language》。
|
||||
<!-- -->
|
||||
> 如果你觉得这个项目不错,请[点击Star一下](https://github.com/numbbbbb/the-swift-programming-language-in-chinese),您的支持我们最大的动力。
|
||||
|
||||
翻译正在进行中,翻译完成的部分会实时同步到这里。您可以到[项目首页](https://github.com/numbbbbb/the-swift-programming-language-in-chinese)查看当前进度。
|
||||
# The Swift Programming Language 中文版
|
||||
|
||||
由于是多人协同翻译,可能会有些术语或者句子翻译不太恰当,如果您在阅读过程中发现此类问题,请直接给我们提 issue 或者 pull request。翻译完成后我们会进行认真的校对,给大家提供一本高质量的 Swift 教程。
|
||||
###这一次,让中国和世界同步
|
||||
|
||||
如果您愿意加入进来,帮助我们进行翻译和校对,请阅读[项目首页](https://github.com/numbbbbb/the-swift-programming-language-in-chinese)中的说明并加入QQ群:364279588,我们期待您的加入,在 Swift 的历史上留下您的足迹!
|
||||
现在是6月12日凌晨4:38,我用了整整一晚上的时间来进行最后的校对,终于可以在12日拿出一个可以发布的版本。
|
||||
|
||||
最后,非常感谢您的阅读,如果您觉得本文不错的话请分享给其他人,您的支持就是我们最大的动力!
|
||||
9天时间,1317个 Star,310个 Fork,超过30人参与翻译和校对工作,项目最高排名GitHub总榜第4。
|
||||
|
||||
设想过很多遍校对完成时的场景,仰天大笑还是泪流满面?真正到了这一刻才发现,疲倦已经不允许我有任何情绪。
|
||||
|
||||
说实话,刚开始发起项目的时候完全没想到会发展成今天这样,我一度计划自己一个人翻译完整本书。万万没想到,会有这么多的人愿意加入并贡献出自己的力量。
|
||||
|
||||
coverxit发给我最后一份文档的时候说,我要去背单词了,我问他,周末要考六级?他说是的。
|
||||
|
||||
pp-prog告诉我,这几天太累了,校对到一半睡着了,醒来又继续做。2点17分,发给我校对完成的文档。
|
||||
|
||||
lifedim说他平时12点就会睡,1点47分,发给我校对后的文档。
|
||||
|
||||
团队里每个人都有自己的事情,上班、上学、创业,但是我们只用了9天就完成整本书的翻译。我不知道大家付出了多少,牺牲了多少,但是我知道,他们的付出必将被这些文字记录下来,即使再过10年,20年,依然熠熠生辉,永不被人遗忘。
|
||||
|
||||
全体人员名单(排名不分先后):
|
||||
|
||||
- [numbbbbb](https://github.com/numbbbbb)
|
||||
- [stanzhai](https://github.com/stanzhai)
|
||||
- [coverxit](https://github.com/coverxit)
|
||||
- [wh1100717](https://github.com/wh1100717)
|
||||
- [TimothyYe](https://github.com/TimothyYe)
|
||||
- [honghaoz](https://github.com/honghaoz)
|
||||
- [lyuka](https://github.com/lyuka)
|
||||
- [JaySurplus](https://github.com/JaySurplus)
|
||||
- [Hawstein](https://github.com/Hawstein)
|
||||
- [geek5nan](https://github.com/geek5nan)
|
||||
- [yankuangshi](https://github.com/yankuangshi)
|
||||
- [xielingwang](https://github.com/xielingwang)
|
||||
- [yulingtianxia](https://github.com/yulingtianxia)
|
||||
- [twlkyao](https://github.com/twlkyao)
|
||||
- [dabing1022](https://github.com/dabing1022)
|
||||
- [vclwei](https://github.com/vclwei)
|
||||
- [fd5788](https://github.com/fd5788)
|
||||
- [siemenliu](https://github.com/siemenliu)
|
||||
- [youkugems](https://github.com/youkugems)
|
||||
- [haolloyin](https://github.com/haolloyin)
|
||||
- [wxstars](https://github.com/wxstars)
|
||||
- [IceskYsl](https://github.com/IceskYsl)
|
||||
- [sg552](https://github.com/sg552)
|
||||
- [superkam](https://github.com/superkam)
|
||||
- [zac1st1k](https://github.com/zac1st1k)
|
||||
- [bzsy](https://github.com/bzsy)
|
||||
- [pyanfield](https://github.com/pyanfield)
|
||||
- [ericzyh](https://github.com/ericzyh)
|
||||
- [peiyucn](https://github.com/peiyucn)
|
||||
- [sunfiled](https://github.com/sunfiled)
|
||||
- [lzw120](https://github.com/lzw120)
|
||||
- [viztor](https://github.com/viztor)
|
||||
- [wongzigii](https://github.com/wongzigii)
|
||||
- [umcsdon](https://github.com/umcsdon)
|
||||
- [zq54zquan](https://github.com/zq54zquan)
|
||||
- [xiehurricane](https://github.com/xiehurricane)
|
||||
- [Jasonbroker](https://github.com/Jasonbroker)
|
||||
- [tualatrix](https://github.com/tualatrix)
|
||||
- [pp-prog](https://github.com/pp-prog)
|
||||
- [088haizi](https://github.com/088haizi)
|
||||
- [baocaixiong](https://github.com/baocaixiong)
|
||||
- [yeahdongcn](https://github.com/yeahdongcn)
|
||||
- [shinyzhu](https://github.com/shinyzhu)
|
||||
- [lslxdx](https://github.com/lslxdx)
|
||||
- [Evilcome](https://github.com/Evilcome)
|
||||
- [zqp](https://github.com/zqp)
|
||||
- [NicePiao](https://github.com/NicePiao)
|
||||
- [LunaticM](https://github.com/LunaticM)
|
||||
- [menlongsheng](https://github.com/menlongsheng)
|
||||
- [lifedim](https://github.com/lifedim)
|
||||
- [happyming](https://github.com/happyming)
|
||||
- [bruce0505](https://github.com/bruce0505)
|
||||
- [Lin-H](https://github.com/Lin-H)
|
||||
- [takalard](https://github.com/takalard)
|
||||
- [dabing1022](https://github.com/dabing1022)
|
||||
- [marsprince](https://github.com/marsprince)
|
||||
|
||||
2
source/SUMMARY.md
Normal file → Executable file
2
source/SUMMARY.md
Normal file → Executable file
@ -15,7 +15,7 @@
|
||||
* [类和结构体](chapter2/09_Classes_and_Structures.md)
|
||||
* [属性](chapter2/10_Properties.md)
|
||||
* [方法](chapter2/11_Methods.md)
|
||||
* [附属脚本](chapter2/12_Subscripts.md)
|
||||
* [下标脚本](chapter2/12_Subscripts.md)
|
||||
* [继承](chapter2/13_Inheritance.md)
|
||||
* [构造过程](chapter2/14_Initialization.md)
|
||||
* [析构过程](chapter2/15_Deinitialization.md)
|
||||
|
||||
30
source/chapter1/01_swift.md
Normal file → Executable file
30
source/chapter1/01_swift.md
Normal file → Executable file
@ -1,13 +1,17 @@
|
||||
# 关于 Swift
|
||||
|
||||
Swift 是一种新的编程语言,用于编写 iOS 和 OS X 应用。Swift 结合了 C 和 Objective-C 的优点并且不受C的兼容性的限制。Swift 使用安全的编程模式并添加了很多新特性,这将使编程更简单,扩展性更强,也更有趣。除此之外,Swift 还支持人见人爱的 Cocoa 和 Cocoa Touch 框架。拥有了这些特性,Swift将重新定义软件开发。
|
||||
|
||||
Swift 的开发从很久之前就开始了。为了给 Swift 打好基础,苹果公司改进了编译器,调试器和框架结构。我们使用自动引用计数(Automatic Reference Counting, ARC)来简化内存管理。我们在 Foundation 和 Cocoa的基础上构建框架栈并将其标准化。Objective-C 本身支持块、集合语法和模块,所以框架可以轻松支持现代编程语言技术。得益于这些基础工作,我们现在可以发布一个新语言,用于未来的苹果软件的开发。
|
||||
|
||||
Objective-C 开发者对于 Swift 并不会感到陌生。它采用了 Objective-C 的命名参数以及动态对象模型,可以无缝对接到现有的 Cocoa 框架,并且可以兼容 Objective-C 代码。在此基础之上,Swift 还有许多新特性并且支持过程式编程和面向对象编程。
|
||||
|
||||
Swift 对于初学者来说也很友好。它是第一个既满足工业标准又像脚本语言一样充满表现力和趣味的编程语言。它支持代码预览,这个革命性的特性可以允许程序员在不编译和运行应用程序的前提下运行 Swift 代码并实时查看结果。
|
||||
|
||||
Swift 将现代编程语言的精华和苹果工程师文化的智慧结合了起来。编译器对性能进行了优化,编程语言对开发进行了优化,两者互不干扰,鱼与熊掌兼得。Swift 即可以用于开发“hello, world”这样的小程序,也可以用于开发一个完整的操作系统。所有的这些特性让 Swift 对于开发者和苹果来说都是一项值得的投资。
|
||||
|
||||
用 Swift 编写 iOS 和 OS X 应用将是一场美妙的体验,Swift 之后也会不断开发新特性和兼容性。我们对 Swift 充满信心,你还在等什么!
|
||||
> 翻译:[numbbbbb](https://github.com/numbbbbb)
|
||||
> 校对:[yeahdongcn](https://github.com/yeahdongcn)
|
||||
|
||||
# 关于 Swift
|
||||
-----------------
|
||||
|
||||
Swift 是一种新的编程语言,用于编写 iOS 和 OS X 应用。Swift 结合了 C 和 Objective-C 的优点并且不受 C 兼容性的限制。Swift 采用安全的编程模式并添加了很多新特性,这将使编程更简单,更灵活,也更有趣。Swift 是基于成熟而且倍受喜爱的 Cocoa 和 Cocoa Touch 框架,它的降临将重新定义软件开发。
|
||||
|
||||
Swift 的开发从很久之前就开始了。为了给 Swift 打好基础,苹果公司改进了编译器,调试器和框架结构。我们使用自动引用计数(Automatic Reference Counting, ARC)来简化内存管理。我们在 Foundation 和 Cocoa 的基础上构建框架栈并将其标准化。Objective-C 本身支持块、集合语法和模块,所以框架可以轻松支持现代编程语言技术。正是得益于这些基础工作,我们现在才能发布这样一个用于未来苹果软件开发的新语言。
|
||||
|
||||
Objective-C 开发者对 Swift 并不会感到陌生。它采用了 Objective-C 的命名参数以及动态对象模型,可以无缝对接到现有的 Cocoa 框架,并且可以兼容 Objective-C 代码。在此基础之上,Swift 还有许多新特性并且支持过程式编程和面向对象编程。
|
||||
|
||||
Swift 对于初学者来说也很友好。它是第一个既满足工业标准又像脚本语言一样充满表现力和趣味的编程语言。它支持代码预览,这个革命性的特性可以允许程序员在不编译和运行应用程序的前提下运行 Swift 代码并实时查看结果。
|
||||
|
||||
Swift 将现代编程语言的精华和苹果工程师文化的智慧结合了起来。编译器对性能进行了优化,编程语言对开发进行了优化,两者互不干扰,鱼与熊掌兼得。Swift 既可以用于开发 “hello, world” 这样的小程序,也可以用于开发一套完整的操作系统。所有的这些特性让 Swift 对于开发者和苹果来说都是一项值得的投资。
|
||||
|
||||
Swift 是编写 iOS 和 OS X 应用的极佳手段,并将伴随着新的特性和功能持续演进。我们对 Swift 充满信心,你还在等什么!
|
||||
|
||||
876
source/chapter1/02_a_swift_tour.md
Normal file → Executable file
876
source/chapter1/02_a_swift_tour.md
Normal file → Executable file
File diff suppressed because it is too large
Load Diff
BIN
source/chapter1/GuidedTour.playground.zip
Normal file
BIN
source/chapter1/GuidedTour.playground.zip
Normal file
Binary file not shown.
8
source/chapter1/chapter1.md
Normal file → Executable file
8
source/chapter1/chapter1.md
Normal file → Executable file
@ -1,4 +1,4 @@
|
||||
# 欢迎使用 Swift
|
||||
|
||||
在本章中您将了解 Swift 的特性和开发历史,并对 Swift 有一个初步的了解。
|
||||
|
||||
# 欢迎使用 Swift
|
||||
|
||||
在本章中您将了解 Swift 的特性和开发历史,并对 Swift 有一个初步的了解。
|
||||
|
||||
|
||||
1243
source/chapter2/01_The_Basics.md
Normal file → Executable file
1243
source/chapter2/01_The_Basics.md
Normal file → Executable file
File diff suppressed because it is too large
Load Diff
913
source/chapter2/02_Basic_Operators.md
Normal file → Executable file
913
source/chapter2/02_Basic_Operators.md
Normal file → Executable file
@ -1,456 +1,457 @@
|
||||
# 基础运算符
|
||||
|
||||
运算符是检查, 改变, 合并值的特殊符号或短语. 例如, 加号 `+` 把计算两个数的和(如 `let i = 1 + 2`). 复杂些的运行算包括逻辑与`&&`(如 `if enteredDoorCode && passedRetinaScan`), 还有自增运算符 `++i` 这样让自身加一的便捷运算.
|
||||
|
||||
Swift支持大部分标准C语言的运算符, 且改进许多特性来减少常规编码错误. 如, 赋值符 `=` 不返回值, 以防止错把等号 `==` 写成赋值号 `=` 而导致Bug. 数值运算符( `+` , `-`, `*`, `/`, `%`等)会检测并不允许值溢出, 以此来避免保存变量时由于变量大于或小于其类型所能承载的范围时导致的异常结果. 当然允许你选择使用Swift的溢出运算符来玩溢出. 具体使用请移步[溢出运算符](Overflow Operators).
|
||||
|
||||
区别于C语言, 在Swift中你可以对浮点数进行取余运算( `%` ), 还提供了C语言没有的表达两数之间的值的区间运算符, ( `a..b` 和 `a...b` ), 这方便我们表达一个区间内的数值.
|
||||
|
||||
本章节只描述了Swift中的简单运算符, [高级运算符](http://#)包含了高级运算符,及如何自定义运算符, 及如何进行自定义类型的运算符重载.
|
||||
|
||||
# 术语
|
||||
|
||||
运算符有一目, 双目和三目运算符.
|
||||
|
||||
一目运算符对单一操作对象操作, 如 `-a`.
|
||||
|
||||
一目运算符分前置符和后置运算符, 前置运算符需紧排操作对象之前, 如 `!b`, 后置运算符需紧跟操作对象之后,如 `i++`,
|
||||
|
||||
双目运算符操作两个操作对象, 如 `2 + 3`. 是中置的, 因为它们出现在两个操作对象之间.
|
||||
|
||||
三目运算符操作三个操作对象, 和C语言一样, Swift只有一个三目运算符, 就是三目条件运算符 `a ? b : c`.
|
||||
|
||||
受运算符影响的值叫操作数, 在表达式 `1 + 2` 中, 加号 `+` 是双目运算符, 它的两个操作数是值 `1` 和 `2`.
|
||||
|
||||
# 赋值运算符
|
||||
|
||||
赋值运算 `a = b`, 表示用 `b` 的值来初始化或更新 `a` 的值.
|
||||
|
||||
```swift
|
||||
let b = 10
|
||||
var a = 5
|
||||
a = b
|
||||
// a 现在等于 10
|
||||
```
|
||||
|
||||
如果赋值的右边是一个多元组, 它的元素可以马上被分解多个变量或变量
|
||||
```
|
||||
let (x, y) = (1, 2)
|
||||
// 现在 x 等于 1, y 等于 2
|
||||
```
|
||||
与C语言和Objective-C不同, Swift的赋值操作并不返回任何值. 所以以下代码是错误的:
|
||||
|
||||
```swift
|
||||
if x = y {
|
||||
// 此句错误, 因为 x = y 并不返回任何值
|
||||
}
|
||||
```
|
||||
|
||||
这个特性使得你不无法把`==`错写成`=`了, 由于`if x = y`是错误代码, Swift从底层帮你避免了这些代码错误.
|
||||
|
||||
# 数值运算
|
||||
|
||||
Swift让所有数值类型都支持了基本的四则运算:
|
||||
|
||||
- 加法 `+`
|
||||
- 减法 `-`
|
||||
- 乘法 `*`
|
||||
- 除法 `/`
|
||||
|
||||
```swift
|
||||
1 + 2 // 等于 3
|
||||
5 - 3 // 等于 2
|
||||
2 * 3 // 等于 6
|
||||
10.0 / 2.5 // 等于 4.0
|
||||
```
|
||||
|
||||
与C语言和Objective-C不同的是, Swift默认不允许在数值运算中出现溢出情况. 但你可以使用Swift的溢出运算符来达到你有目的的溢出, (如 `a &+ b` ). 详情请移步: [溢出运算符](Overflow Operators).
|
||||
|
||||
加法操作 `+` 也用于字符串的拼接:
|
||||
|
||||
```swift
|
||||
"hello, " + "world" // 等于 "hello, world"
|
||||
```
|
||||
|
||||
两个字符类型或一个字符类型和一个字符串类型, 相加会生成一个新的字符串类型:
|
||||
|
||||
```swift
|
||||
let dog: Character = "d"
|
||||
let cow: Character = "c"
|
||||
let dogCow = dog + cow
|
||||
// 译者注: 原谅的引号内是很可爱的小狗和小牛, 但win os下不支持表情字符, 所以改成了普通字符
|
||||
// dogCow 现在是 "dc"
|
||||
```
|
||||
详细请点击 [字符,字符串的拼接](http://#).
|
||||
|
||||
# 求余运算
|
||||
|
||||
求余运算 `a % b` 是计算 `b` 的多少倍刚刚好可以容入 `a` , 多出来的那部分叫余数.
|
||||
|
||||
> 注意
|
||||
|
||||
> 求余运算(%)在其他语言也叫取模运算. 然而严格说来, 我们看该运算符对负数的操作结果, `求余` 比 `取模` 更合适些.
|
||||
|
||||
我们来谈谈取余是怎么回事, 计算 `9 % 4`, 你先计算出4的多少倍会刚好可以容入 `9` 中.
|
||||
|
||||
2倍, 非常好, 那余数是1 (用'*'标出)
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>1 </td>
|
||||
<td>2 </td>
|
||||
<td>3 </td>
|
||||
<td>4 </td>
|
||||
<td>5 </td>
|
||||
<td>6 </td>
|
||||
<td>7 </td>
|
||||
<td>8 </td>
|
||||
<td>9 </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="4">4</td>
|
||||
<td colspan="4">4</td>
|
||||
<td>1*</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
在Swift中这么来表达
|
||||
|
||||
```swift
|
||||
9 % 4 // 等于 1
|
||||
```
|
||||
|
||||
为了得到 `a % b` 的结果, `%`计算了以下等式, 并输出`余数`作为结果:
|
||||
```
|
||||
a = (b × 倍数) + 余数
|
||||
```
|
||||
当`倍数`取最大值的时候, 就会刚好可以容入 `a` 中.
|
||||
|
||||
把 `9` 和 `4` 代入等式中, 我们得 `1`:
|
||||
|
||||
```swift
|
||||
9 = (4 × 2) + 1
|
||||
```
|
||||
|
||||
同样的方法, 我来们计算 `-9 % 4` :
|
||||
```
|
||||
-9 % 4 // 等于 -1
|
||||
```
|
||||
|
||||
把 `-9` 和 `4` 代入等式, `-2` 是取到的最大整数:
|
||||
|
||||
```swift
|
||||
-9 = (4 × -2) + -1
|
||||
```
|
||||
|
||||
余数是 `-1`.
|
||||
|
||||
在对负数 `-b` 求余时, `-b`的符号会被忽略. 这意味着 `a % b` 和 `a % -b`的结果是相同的.
|
||||
|
||||
## 浮点数求余计算
|
||||
|
||||
不同于C和Objective-C, Swift中是可以对浮点数进行求余的.
|
||||
|
||||
```swift
|
||||
8 % 2.5 // 等于 0.5
|
||||
```
|
||||
|
||||
这个例子中, 8除于2.5等于3余0.5, 所以结果是0.5.
|
||||
|
||||
# 自增和自增运算
|
||||
|
||||
和C一样, Swift也提供了方便对变量本身加1或减1的自增 `++` 和自减 `--` 的运算符. 其操作对象可以是整形和浮点型。
|
||||
|
||||
```
|
||||
var i = 0
|
||||
++i // 现在 i = 1
|
||||
```
|
||||
|
||||
每调用一次 `++i`, `i` 的值就会加1.
|
||||
实际上, `++i` 是 `i = i + 1` 的简写, 而 `--i` 是 `i = i - 1`的简写.
|
||||
|
||||
`++` 和 `--`既是前置又是后置运算. `++i`, `i++`, `--i` 和 `i--` 都是有效的写法.
|
||||
|
||||
我们需要注意的是这些运算符修改了 `i` 后有一个返回值. 如果你只想修改 `i` 的值, 那你就可以忽略这个返回值. 但如果你想使用返回值, 你就需要留意前置和后置操作的返回值是不同的.
|
||||
|
||||
当 `++` 前置的时候, 先自増再返回.
|
||||
|
||||
当 `++` 后置的时候, 先返回再自增.
|
||||
|
||||
不懂? 我们看例子:
|
||||
|
||||
```swift
|
||||
var a = 0
|
||||
let b = ++a // a 和 b 现在都是 1
|
||||
let c = a++ // a 现在 2, 但 c 是 a 自增前的值 1
|
||||
```
|
||||
|
||||
上述例子, `let b = ++a`, 先把 `a` 加1了再返回 `a` 的值. 所以 `a` 和 `b` 都是新值 `1`.
|
||||
|
||||
而 `let c = a++`, 是先返回了 `a` 的值, 然后 `a` 才加1. 所以 `c` 得到了 `a` 的旧值1, 而 `a` 加1后变成2.
|
||||
|
||||
除非你需要使用 `i++` 的特性, 不然推荐你使用 `++i` 和 `--i`, 因为先修改后返回这样的行为更符合我们的逻辑.
|
||||
|
||||
|
||||
# 单目负号
|
||||
|
||||
数值的正负号可以使用前缀 `-` (即单目负号) 来切换:
|
||||
|
||||
```swift
|
||||
let three = 3
|
||||
let minusThree = -three // minusThree 等于 -3
|
||||
let plusThree = -minusThree // plusThree 等于 3, 或 "负负3"
|
||||
```
|
||||
|
||||
单目负号写在操作数之前, 中间没有空格.
|
||||
|
||||
# 单目正号
|
||||
|
||||
单目正号 `+` 不做任何改变地返回操作数的值.
|
||||
|
||||
```swift
|
||||
let minusSix = -6
|
||||
let alsoMinusSix = +minusSix // alsoMinusSix 等于 -6
|
||||
```
|
||||
虽然单目 `+` 做无用功, 但当你在使用单目负号来表达负数时, 你可以使用单目正号来表达正数, 如此你的代码会具有对称美.
|
||||
|
||||
|
||||
# 复合赋值
|
||||
|
||||
如同强大的C语言, Swift也提供把其他运算符和赋值运算 `=` 组合的复合赋值运算符, 加赋运算 `+=` 是其中一个例子:
|
||||
|
||||
```swift
|
||||
var a = 1
|
||||
a += 2 // a 现在是 3
|
||||
```
|
||||
|
||||
表达式 `a += 2` 是 `a = a + 2` 的简写, 一个加赋运算就把加法和赋值两件事完成了.
|
||||
|
||||
> 注意:
|
||||
|
||||
> 复合赋值运算没有返回值, `let b = a += 2` 这类代码是错误. 这不同于上面提到的自增和自减运算符.
|
||||
|
||||
[表达式](http://#)里有复合运算符的完整列表.
|
||||
|
||||
# 比较运算
|
||||
|
||||
所有标准C中的比较运算都可以在Swift中使用.
|
||||
|
||||
- 等于 `a == b`
|
||||
- 不等于 `a != b`
|
||||
- 大于 `a > b`
|
||||
- 小于 `a < b`
|
||||
- 大于等于 `a >= b`
|
||||
- 小于等于 `a <= b`
|
||||
|
||||
> 注意:
|
||||
|
||||
> Swift也提供恒等 `===` 和不恒等 `!==` 这两个比较符来判断两个对象是否引用同一个对象实例. 更多细节在 [类与结构](Classes and Structures).
|
||||
|
||||
每个比较运算都返回了一个标识表达式是否成立的布尔值:
|
||||
|
||||
```swift
|
||||
1 == 1 // true, 因为 1 等于 1
|
||||
2 != 1 // true, 因为 2 不等于 1
|
||||
2 > 1 // true, 因为 2 大于 1
|
||||
1 < 2 // true, 因为 1 小于2
|
||||
1 >= 1 // true, 因为 1 大于等于 1
|
||||
2 <= 1 // false, 因为 2 并不小于等于 1
|
||||
```
|
||||
|
||||
比较运算多用于条件语句, 如 `if` 条件:
|
||||
|
||||
```swift
|
||||
let name = "world"
|
||||
if name == "world" {
|
||||
println("hello, world")
|
||||
} else {
|
||||
println("对不起, \(name), 我不认识你!")
|
||||
}
|
||||
// 输出 "hello, world", 因为 `name` 就是等于 "world"
|
||||
```
|
||||
|
||||
关于 `if` 语句, 请看 [控制流](Control Flow).
|
||||
|
||||
# 三目条件运算
|
||||
|
||||
三目条件运算的特殊在于它是有三个操作数的运算符, 它的原型是 `问题 ? 答案1 : 答案2`. 它简洁地表达根据 `问题` 成立与否作出二选一的操作. 如果 `问题` 成立, 返回 `答案1` 的结果; 如果不成立, 返回 `答案2` 的结果.
|
||||
|
||||
使用三目条件运算简化了以下代码:
|
||||
|
||||
```swift
|
||||
if question: {
|
||||
answer1
|
||||
}
|
||||
else {
|
||||
answer2
|
||||
}
|
||||
```
|
||||
|
||||
这里有个计算表格行高的例子. 如果有表头, 那行高应比内容高度要高出50像素; 如果没有表头, 只需高出20像素.
|
||||
|
||||
```swift
|
||||
let contentHeight = 40
|
||||
let hasHeader = true
|
||||
let rowHeight = contentHeight + (hasHeader ? 50 : 20)
|
||||
// rowHeight 现在是 90
|
||||
```
|
||||
|
||||
这样写会比下面的代码简洁:
|
||||
|
||||
```swift
|
||||
let contentHeight = 40
|
||||
let hasHeader = true
|
||||
var rowHeight = contentHeight
|
||||
if hasHeader {
|
||||
rowHeight = rowHeight + 50
|
||||
} else {
|
||||
rowHeight = rowHeight + 20
|
||||
}
|
||||
// rowHeight 现在是 90
|
||||
```
|
||||
|
||||
第一段代码例子使用了三目条件运算, 所以一行代码就能让我们得到正确答案. 这比第二段代码简洁得多, 无需将 `rowHeight` 定义成变量, 因为它的值无需在 `if` 语句中改变.
|
||||
|
||||
三目条件运算提供有效率且便捷的方式来表达二选一的选择. 需要注意的事, 过度使用三目条件运算就会由简洁的代码变成难懂的代码. 我们应避免在一个组合语句使用多个三目条件运算符.
|
||||
|
||||
# 区间运算符
|
||||
|
||||
Swift提供了两个方便表达一个区间的值的运算符.
|
||||
|
||||
## 闭区间运算符
|
||||
闭区间运算符 `a...b` 定义一个包含从 `a` 到 `b` (包括 `a` 和 `b`)的所有值的区间.
|
||||
|
||||
闭区间运算符在迭代一个区间的所有值时是非常有用的, 如在 `for-in` 循环中:
|
||||
|
||||
```swift
|
||||
for index in 1...5 {
|
||||
println("\(index) * 5 = \(index * 5)")
|
||||
}
|
||||
// 1 * 5 = 5
|
||||
// 2 * 5 = 10
|
||||
// 3 * 5 = 15
|
||||
// 4 * 5 = 20
|
||||
// 5 * 5 = 25
|
||||
```
|
||||
|
||||
关于 `for-in`, 请看 [控制流](Control Flow).
|
||||
|
||||
## 半闭区间
|
||||
|
||||
半闭区间 `a..b` 定义一个从 `a` 到 `b` 但不包括 `b` 的区间.
|
||||
之所以称为半闭区间, 是因为该区间包含第一个值而不包括最后的值.
|
||||
|
||||
半闭区间的实用性在于当你使用一个0始的列表(如数组)时, 非常方便地从0数到列表的长度.
|
||||
|
||||
```swift
|
||||
let names = ["Anna", "Alex", "Brian", "Jack"]
|
||||
let count = names.count
|
||||
for i in 0..count {
|
||||
println("第 \(i + 1) 个人叫 \(names[i])")
|
||||
}
|
||||
// 第 1 个人叫 Anna
|
||||
// 第 2 个人叫 Alex
|
||||
// 第 3 个人叫 Brian
|
||||
// 第 4 个人叫 Jack
|
||||
```
|
||||
|
||||
> 注意: 数组有4个元素, 但 `0..count` 只数到 3 (最后一个元素的下标), 因为它是半闭区间. 关于数组, 请查阅 [数组](Arrays).
|
||||
|
||||
# 逻辑运算
|
||||
|
||||
逻辑运算的操作对象是逻辑布尔值. Swift支持基于C语言的三个标准逻辑运算.
|
||||
|
||||
- 逻辑非 `!a`
|
||||
- 逻辑与 `a && b`
|
||||
- 逻辑或 `a || b`
|
||||
|
||||
## 逻辑非
|
||||
|
||||
逻辑非运算 `!a` 对一个布尔值取反, 使得 `true` 变 `false`, `false` 变 `true`.
|
||||
|
||||
它是一个前置运算符, 需出现在操作数之前, 且不加空格. 读作 `非 a`, 然后我们看以下例子:
|
||||
|
||||
```swift
|
||||
let allowedEntry = false
|
||||
if !allowedEntry {
|
||||
println("ACCESS DENIED")
|
||||
}
|
||||
// prints "ACCESS DENIED"
|
||||
```
|
||||
|
||||
`if !allowedEntry`语句可以读作 "如果 非 alowed entry.", 接下一行代码只有在如果 "非 allow entry" 为 `true`, 即 `allowEntry` 为 `false` 时被执行.
|
||||
|
||||
在示例代码中, 小心地选择布尔常量或变量有助于代码的可读性, 并且避免使用双重逻辑非运算, 或混乱的逻辑语句.
|
||||
|
||||
## 逻辑与
|
||||
逻辑与 `a && b` 表达了只有 `a` 和 `b` 的值都为 `true` 时, 整个表达式的值才会是 `true` .
|
||||
|
||||
只要任意一个值为 `false`, 整个表达式的值就为 `false`. 事实上, 如果第一个值为 `false`, 那么是不去计算第二个值的, 因为它已经不可能影响整个表达式的结果了. 这被称做 "短路计算".
|
||||
|
||||
以下例子, 只有两个值都为值的时候才允许进入:
|
||||
|
||||
```swift
|
||||
let enteredDoorCode = true
|
||||
let passedRetinaScan = false
|
||||
if enteredDoorCode && passedRetinaScan {
|
||||
println("Welcome!")
|
||||
} else {
|
||||
println("ACCESS DENIED")
|
||||
}
|
||||
// 输出 "ACCESS DENIED
|
||||
```
|
||||
|
||||
## 逻辑或
|
||||
逻辑或 `a || b` 是一个由两个连续的 `|` 组成的中置运算符. 它表示了两个逻辑表达式的其中一个为 `true`, 整个表达式就为 `true`.
|
||||
|
||||
同逻辑与运算类似, 逻辑或也是"短路计算"的, 当左端的表达式为 `true` 时, 将不计算右边的表达式了, 因为它不可能改变整个表达式的值了.
|
||||
|
||||
以下示例代码中, 第一个布尔值 `hasDoorKey` 为 `false`, 但第二个值 `knowsOverridePassword` 为 `true`, 所以整个表达是 `true`, 于是允许进入:
|
||||
|
||||
```swift
|
||||
let hasDoorKey = false
|
||||
let knowsOverridePassword = true
|
||||
if hasDoorKey || knowsOverridePassword {
|
||||
println("Welcome!")
|
||||
} else {
|
||||
println("ACCESS DENIED")
|
||||
}
|
||||
// 输出 "Welcome!"
|
||||
```
|
||||
|
||||
## 组合逻辑
|
||||
|
||||
我们可以组合多个逻辑运算来表达一个复合逻辑:
|
||||
|
||||
```swift
|
||||
if enteredDoorCode && passedRetinaScan || hasDoorKey || knowsOverridePassword {
|
||||
println("Welcome!")
|
||||
} else {
|
||||
println("ACCESS DENIED")
|
||||
}
|
||||
// 输出 "Welcome!"
|
||||
```
|
||||
|
||||
这个例子使用了含多个 `&&` 和 `||` 的复合逻辑. 但无论怎样, `&&` 和 `||` 始终只能操作两个值. 所以这实际是三个简单逻辑连续操作的结果. 我们来解读一下:
|
||||
|
||||
如果我们输入了正确的密码并通过了视网膜扫描; 或者我们有一把有效的钥匙; 又或者我们知道紧急情况下重置的密码, 我们就能把门打开进入.
|
||||
|
||||
前两种情况, 我们都不满足, 所以前两个简单逻辑的结果是 `false`, 但是我们是知道紧急情况下重置的密码的, 所以整个复杂表达式的值还是 `true`.
|
||||
|
||||
## 使用括号来明确优先级
|
||||
|
||||
为了一个复杂表达式更容易读懂, 在合适的地方使用括号来明确优先级是很有效的, 虽然它并非必要的. 在上个关于门的权限的例子中, 我们给第一个部分加个括号, 使用它看起来逻辑更明确.
|
||||
|
||||
```swift
|
||||
if (enteredDoorCode && passedRetinaScan) || hasDoorKey || knowsOverridePassword {
|
||||
println("Welcome!")
|
||||
} else {
|
||||
println("ACCESS DENIED")
|
||||
}
|
||||
// prints "Welcome!"
|
||||
```
|
||||
|
||||
这括号使得前两个值被看成整个逻辑表达中独立的一个部分. 虽然有括号和没括号的输出结果是一样的, 但对于读代码的人来说有括号的代码更清晰.
|
||||
|
||||
可读性比简洁性更重要, 请在可以让你代码变清晰地地方加个括号吧!
|
||||
> 翻译:[xielingwang](https://github.com/xielingwang)
|
||||
> 校对:[Evilcome](https://github.com/Evilcome)
|
||||
|
||||
# 基本运算符
|
||||
-----------------
|
||||
|
||||
本页包含内容:
|
||||
|
||||
- [术语](#terminology)
|
||||
- [赋值运算符](#assignment_operator)
|
||||
- [数值运算符](#arithmetic_operators)
|
||||
- [组合赋值运算符(Compound Assignment Operators)](#compound_assignment_operators)
|
||||
- [比较运算符](#comparison_operators)
|
||||
- [三元条件运算符(Ternary Conditional Operator)](#ternary_conditional_operator)
|
||||
- [区间运算符](#range_operators)
|
||||
- [逻辑运算符](#logical_operators)
|
||||
|
||||
运算符是检查、改变、合并值的特殊符号或短语。例如,加号`+`将两个数相加(如`let i = 1 + 2`)。复杂些的运算例如逻辑与运算符`&&`(如`if enteredDoorCode && passedRetinaScan`),或让 i 值加1的便捷自增运算符`++i`等。
|
||||
|
||||
Swift 支持大部分标准 C 语言的运算符,且改进许多特性来减少常规编码错误。如:赋值符(`=`)不返回值,以防止把想要判断相等运算符(`==`)的地方写成赋值符导致的错误。数值运算符(`+`,`-`,`*`,`/`,`%`等)会检测并不允许值溢出,以此来避免保存变量时由于变量大于或小于其类型所能承载的范围时导致的异常结果。当然允许你使用 Swift 的溢出运算符来实现溢出。详情参见[溢出运算符](23_Advanced_Operators.html#overflow_operators)。
|
||||
|
||||
区别于 C 语言,在 Swift 中你可以对浮点数进行取余运算(`%`),Swift 还提供了 C 语言没有的表达两数之间的值的区间运算符,(`a..b`和`a...b`),这方便我们表达一个区间内的数值。
|
||||
|
||||
本章节只描述了 Swift 中的基本运算符,[高级运算符](23_Advanced_Operators.html)包含了高级运算符,及如何自定义运算符,及如何进行自定义类型的运算符重载。
|
||||
|
||||
<a name="terminology"></a>
|
||||
## 术语
|
||||
|
||||
运算符有一元、二元和三元运算符。
|
||||
|
||||
- 一元运算符对单一操作对象操作(如`-a`)。一元运算符分前置符和后置运算符,前置运算符需紧排操作对象之前(如`!b`),后置运算符需紧跟操作对象之后(如`i++`)。
|
||||
- 二元运算符操作两个操作对象(如`2 + 3`),是中置的,因为它们出现在两个操作对象之间。
|
||||
- 三元运算符操作三个操作对象,和 C 语言一样,Swift 只有一个三元运算符,就是三元条件运算符(`a ? b : c`)。
|
||||
|
||||
受运算符影响的值叫操作数,在表达式`1 + 2`中,加号`+`是二元运算符,它的两个操作数是值`1`和`2`。
|
||||
|
||||
<a name="assignment_operator"></a>
|
||||
## 赋值运算符
|
||||
|
||||
赋值运算(`a = b`),表示用`b`的值来初始化或更新`a`的值:
|
||||
|
||||
```swift
|
||||
let b = 10
|
||||
var a = 5
|
||||
a = b
|
||||
// a 现在等于 10
|
||||
```
|
||||
|
||||
如果赋值的右边是一个多元组,它的元素可以马上被分解多个变量或变量:
|
||||
|
||||
```swiflt
|
||||
let (x, y) = (1, 2)
|
||||
// 现在 x 等于 1, y 等于 2
|
||||
```
|
||||
|
||||
与 C 语言和 Objective-C 不同,Swift 的赋值操作并不返回任何值。所以以下代码是错误的:
|
||||
|
||||
```swift
|
||||
if x = y {
|
||||
// 此句错误, 因为 x = y 并不返回任何值
|
||||
}
|
||||
```
|
||||
|
||||
这个特性使你无法把(`==`)错写成(`=`),由于`if x = y`是错误代码,Swift 从底层帮你避免了这些错误代码。
|
||||
|
||||
<a name="arithmetic_operators"></a>
|
||||
## 数值运算
|
||||
|
||||
Swift 中所有数值类型都支持了基本的四则运算:
|
||||
|
||||
- 加法(`+`)
|
||||
- 减法(`-`)
|
||||
- 乘法(`*`)
|
||||
- 除法(`/`)
|
||||
|
||||
```swift
|
||||
1 + 2 // 等于 3
|
||||
5 - 3 // 等于 2
|
||||
2 * 3 // 等于 6
|
||||
10.0 / 2.5 // 等于 4.0
|
||||
```
|
||||
|
||||
与 C 语言和 Objective-C 不同的是,Swift 默认不允许在数值运算中出现溢出情况。但你可以使用 Swift 的溢出运算符来达到你有目的的溢出(如`a &+ b`)。详情参见[溢出运算符](23_Advanced_Operators.html#overflow_operators)。
|
||||
|
||||
加法运算符也可用于`String`的拼接:
|
||||
|
||||
```swift
|
||||
"hello, " + "world" // 等于 "hello, world"
|
||||
```
|
||||
|
||||
两个`Character`值或一个`String`和一个`Character`值,相加会生成一个新的`String`值:
|
||||
|
||||
```swift
|
||||
let dog: Character = "d"
|
||||
let cow: Character = "c"
|
||||
let dogCow = dog + cow
|
||||
// 译者注: 原来的引号内是很可爱的小狗和小牛, 但win os下不支持表情字符, 所以改成了普通字符
|
||||
// dogCow 现在是 "dc"
|
||||
```
|
||||
|
||||
详情参见[字符,字符串的拼接](03_Strings_and_Characters.html#concatenating_strings_and_characters)。
|
||||
|
||||
### 求余运算
|
||||
|
||||
求余运算(`a % b`)是计算`b`的多少倍刚刚好可以容入`a`,返回多出来的那部分(余数)。
|
||||
|
||||
>注意:
|
||||
求余运算(`%`)在其他语言也叫取模运算。然而严格说来,我们看该运算符对负数的操作结果,"求余"比"取模"更合适些。
|
||||
|
||||
我们来谈谈取余是怎么回事,计算`9 % 4`,你先计算出`4`的多少倍会刚好可以容入`9`中:
|
||||
|
||||

|
||||
|
||||
2倍,非常好,那余数是1(用橙色标出)
|
||||
|
||||
在 Swift 中这么来表达:
|
||||
|
||||
```swift
|
||||
9 % 4 // 等于 1
|
||||
```
|
||||
|
||||
为了得到`a % b`的结果,`%`计算了以下等式,并输出`余数`作为结果:
|
||||
|
||||
*a = (b × 倍数) + 余数*
|
||||
|
||||
当`倍数`取最大值的时候,就会刚好可以容入`a`中。
|
||||
|
||||
把`9`和`4`代入等式中,我们得`1`:
|
||||
|
||||
```swift
|
||||
9 = (4 × 2) + 1
|
||||
```
|
||||
|
||||
同样的方法,我来们计算 `-9 % 4`:
|
||||
|
||||
```swift
|
||||
-9 % 4 // 等于 -1
|
||||
```
|
||||
|
||||
把`-9`和`4`代入等式,`-2`是取到的最大整数:
|
||||
|
||||
```swift
|
||||
-9 = (4 × -2) + -1
|
||||
```
|
||||
|
||||
余数是`-1`。
|
||||
|
||||
在对负数`b`求余时,`b`的符号会被忽略。这意味着 `a % b` 和 `a % -b`的结果是相同的。
|
||||
|
||||
### 浮点数求余计算
|
||||
|
||||
不同于 C 语言和 Objective-C,Swift 中是可以对浮点数进行求余的。
|
||||
|
||||
```swift
|
||||
8 % 2.5 // 等于 0.5
|
||||
```
|
||||
|
||||
这个例子中,`8`除于`2.5`等于`3`余`0.5`,所以结果是一个`Double`值`0.5`。
|
||||
|
||||

|
||||
|
||||
### 自增和自增运算
|
||||
|
||||
和 C 语言一样,Swift 也提供了方便对变量本身加1或减1的自增(`++`)和自减(`--`)的运算符。其操作对象可以是整形和浮点型。
|
||||
|
||||
```swift
|
||||
var i = 0
|
||||
++i // 现在 i = 1
|
||||
```
|
||||
|
||||
每调用一次`++i`,`i`的值就会加1。实际上,`++i`是`i = i + 1`的简写,而`--i`是`i = i - 1`的简写。
|
||||
|
||||
`++`和`--`既是前置又是后置运算。`++i`,`i++`,`--i`和`i--`都是有效的写法。
|
||||
|
||||
我们需要注意的是这些运算符修改了`i`后有一个返回值。如果你只想修改`i`的值,那你就可以忽略这个返回值。但如果你想使用返回值,你就需要留意前置和后置操作的返回值是不同的。
|
||||
|
||||
- 当`++`前置的时候,先自増再返回。
|
||||
|
||||
- 当`++`后置的时候,先返回再自增。
|
||||
|
||||
例如:
|
||||
|
||||
```swift
|
||||
var a = 0
|
||||
let b = ++a // a 和 b 现在都是 1
|
||||
let c = a++ // a 现在 2, 但 c 是 a 自增前的值 1
|
||||
```
|
||||
|
||||
上述例子,`let b = ++a`先把`a`加1了再返回`a`的值。所以`a`和`b`都是新值`1`。
|
||||
|
||||
而`let c = a++`,是先返回了`a`的值,然后`a`才加1。所以`c`得到了`a`的旧值1,而`a`加1后变成2。
|
||||
|
||||
除非你需要使用`i++`的特性,不然推荐你使用`++i`和`--i`,因为先修改后返回这样的行为更符合我们的逻辑。
|
||||
|
||||
|
||||
### 一元负号
|
||||
|
||||
数值的正负号可以使用前缀`-`(即一元负号)来切换:
|
||||
|
||||
```swift
|
||||
let three = 3
|
||||
let minusThree = -three // minusThree 等于 -3
|
||||
let plusThree = -minusThree // plusThree 等于 3, 或 "负负3"
|
||||
```
|
||||
|
||||
一元负号(`-`)写在操作数之前,中间没有空格。
|
||||
|
||||
### 一元正号
|
||||
|
||||
一元正号(`+`)不做任何改变地返回操作数的值。
|
||||
|
||||
```swift
|
||||
let minusSix = -6
|
||||
let alsoMinusSix = +minusSix // alsoMinusSix 等于 -6
|
||||
```
|
||||
虽然一元`+`做无用功,但当你在使用一元负号来表达负数时,你可以使用一元正号来表达正数,如此你的代码会具有对称美。
|
||||
|
||||
|
||||
<a name="compound_assignment_operators"></a>
|
||||
## 复合赋值(Compound Assignment Operators)
|
||||
|
||||
如同强大的 C 语言,Swift 也提供把其他运算符和赋值运算(`=`)组合的复合赋值运算符,加赋运算(`+=`)是其中一个例子:
|
||||
|
||||
```swift
|
||||
var a = 1
|
||||
a += 2 // a 现在是 3
|
||||
```
|
||||
|
||||
表达式`a += 2`是`a = a + 2`的简写,一个加赋运算就把加法和赋值两件事完成了。
|
||||
|
||||
>注意:
|
||||
复合赋值运算没有返回值,`let b = a += 2`这类代码是错误。这不同于上面提到的自增和自减运算符。
|
||||
|
||||
在[表达式](../chapter3/04_Expressions.html)章节里有复合运算符的完整列表。
|
||||
|
||||
<a name="comparison_operators"></a>
|
||||
## 比较运算
|
||||
|
||||
所有标准 C 语言中的比较运算都可以在 Swift 中使用。
|
||||
|
||||
- 等于(`a == b`)
|
||||
- 不等于(`a != b`)
|
||||
- 大于(`a > b`)
|
||||
- 小于(`a < b`)
|
||||
- 大于等于(`a >= b`)
|
||||
- 小于等于(`a <= b`)
|
||||
|
||||
> 注意:
|
||||
Swift 也提供恒等`===`和不恒等`!==`这两个比较符来判断两个对象是否引用同一个对象实例。更多细节在[类与结构](09_Classes_and_Structures.html)。
|
||||
|
||||
每个比较运算都返回了一个标识表达式是否成立的布尔值:
|
||||
|
||||
```swift
|
||||
1 == 1 // true, 因为 1 等于 1
|
||||
2 != 1 // true, 因为 2 不等于 1
|
||||
2 > 1 // true, 因为 2 大于 1
|
||||
1 < 2 // true, 因为 1 小于2
|
||||
1 >= 1 // true, 因为 1 大于等于 1
|
||||
2 <= 1 // false, 因为 2 并不小于等于 1
|
||||
```
|
||||
|
||||
比较运算多用于条件语句,如`if`条件:
|
||||
|
||||
```swift
|
||||
let name = "world"
|
||||
if name == "world" {
|
||||
println("hello, world")
|
||||
} else {
|
||||
println("I'm sorry \(name), but I don't recognize you")
|
||||
}
|
||||
// 输出 "hello, world", 因为 `name` 就是等于 "world"
|
||||
```
|
||||
|
||||
关于`if`语句,请看[控制流](05_Control_Flow.html)。
|
||||
|
||||
<a name="ternary_conditional_operator"></a>
|
||||
## 三元条件运算(Ternary Conditional Operator)
|
||||
|
||||
三元条件运算的特殊在于它是有三个操作数的运算符,它的原型是 `问题 ? 答案1 : 答案2`。它简洁地表达根据`问题`成立与否作出二选一的操作。如果`问题`成立,返回`答案1`的结果; 如果不成立,返回`答案2`的结果。
|
||||
|
||||
使用三元条件运算简化了以下代码:
|
||||
|
||||
```swift
|
||||
if question: {
|
||||
answer1
|
||||
} else {
|
||||
answer2
|
||||
}
|
||||
```
|
||||
|
||||
这里有个计算表格行高的例子。如果有表头,那行高应比内容高度要高出50像素; 如果没有表头,只需高出20像素。
|
||||
|
||||
```swift
|
||||
let contentHeight = 40
|
||||
let hasHeader = true
|
||||
let rowHeight = contentHeight + (hasHeader ? 50 : 20)
|
||||
// rowHeight 现在是 90
|
||||
```
|
||||
|
||||
这样写会比下面的代码简洁:
|
||||
|
||||
```swift
|
||||
let contentHeight = 40
|
||||
let hasHeader = true
|
||||
var rowHeight = contentHeight
|
||||
if hasHeader {
|
||||
rowHeight = rowHeight + 50
|
||||
} else {
|
||||
rowHeight = rowHeight + 20
|
||||
}
|
||||
// rowHeight 现在是 90
|
||||
```
|
||||
|
||||
第一段代码例子使用了三元条件运算,所以一行代码就能让我们得到正确答案。这比第二段代码简洁得多,无需将`rowHeight`定义成变量,因为它的值无需在`if`语句中改变。
|
||||
|
||||
三元条件运算提供有效率且便捷的方式来表达二选一的选择。需要注意的事,过度使用三元条件运算就会由简洁的代码变成难懂的代码。我们应避免在一个组合语句使用多个三元条件运算符。
|
||||
|
||||
<a name="range_operators"></a>
|
||||
## 区间运算符
|
||||
|
||||
Swift 提供了两个方便表达一个区间的值的运算符。
|
||||
|
||||
### 闭区间运算符
|
||||
闭区间运算符(`a...b`)定义一个包含从`a`到`b`(包括`a`和`b`)的所有值的区间。
|
||||
|
||||
闭区间运算符在迭代一个区间的所有值时是非常有用的,如在`for-in`循环中:
|
||||
|
||||
```swift
|
||||
for index in 1...5 {
|
||||
println("\(index) * 5 = \(index * 5)")
|
||||
}
|
||||
// 1 * 5 = 5
|
||||
// 2 * 5 = 10
|
||||
// 3 * 5 = 15
|
||||
// 4 * 5 = 20
|
||||
// 5 * 5 = 25
|
||||
```
|
||||
|
||||
关于`for-in`,请看[控制流](05_Control_Flow.html)。
|
||||
|
||||
### 半闭区间
|
||||
|
||||
半闭区间(`a..b`)定义一个从`a`到`b`但不包括`b`的区间。
|
||||
之所以称为半闭区间,是因为该区间包含第一个值而不包括最后的值。
|
||||
|
||||
半闭区间的实用性在于当你使用一个0始的列表(如数组)时,非常方便地从0数到列表的长度。
|
||||
|
||||
```swift
|
||||
let names = ["Anna", "Alex", "Brian", "Jack"]
|
||||
let count = names.count
|
||||
for i in 0..count {
|
||||
println("第 \(i + 1) 个人叫 \(names[i])")
|
||||
}
|
||||
// 第 1 个人叫 Anna
|
||||
// 第 2 个人叫 Alex
|
||||
// 第 3 个人叫 Brian
|
||||
// 第 4 个人叫 Jack
|
||||
```
|
||||
|
||||
数组有4个元素,但`0..count`只数到3(最后一个元素的下标),因为它是半闭区间。关于数组,请查阅[数组](04_Collection_Types.html#arrays)。
|
||||
|
||||
<a name="logical_operators"></a>
|
||||
## 逻辑运算
|
||||
|
||||
逻辑运算的操作对象是逻辑布尔值。Swift 支持基于 C 语言的三个标准逻辑运算。
|
||||
|
||||
- 逻辑非(`!a`)
|
||||
- 逻辑与(`a && b`)
|
||||
- 逻辑或(`a || b`)
|
||||
|
||||
### 逻辑非
|
||||
|
||||
逻辑非运算(`!a`)对一个布尔值取反,使得`true`变`false`,`false`变`true`。
|
||||
|
||||
它是一个前置运算符,需出现在操作数之前,且不加空格。读作`非 a`,然后我们看以下例子:
|
||||
|
||||
```swift
|
||||
let allowedEntry = false
|
||||
if !allowedEntry {
|
||||
println("ACCESS DENIED")
|
||||
}
|
||||
// 输出 "ACCESS DENIED"
|
||||
```
|
||||
|
||||
`if !allowedEntry`语句可以读作 "如果 非 alowed entry。",接下一行代码只有在如果 "非 allow entry" 为`true`,即`allowEntry`为`false`时被执行。
|
||||
|
||||
在示例代码中,小心地选择布尔常量或变量有助于代码的可读性,并且避免使用双重逻辑非运算,或混乱的逻辑语句。
|
||||
|
||||
### 逻辑与
|
||||
逻辑与(`a && b`)表达了只有`a`和`b`的值都为`true`时,整个表达式的值才会是`true`。
|
||||
|
||||
只要任意一个值为`false`,整个表达式的值就为`false`。事实上,如果第一个值为`false`,那么是不去计算第二个值的,因为它已经不可能影响整个表达式的结果了。这被称做 "短路计算(short-circuit evaluation)"。
|
||||
|
||||
以下例子,只有两个`Bool`值都为`true`值的时候才允许进入:
|
||||
|
||||
```swift
|
||||
let enteredDoorCode = true
|
||||
let passedRetinaScan = false
|
||||
if enteredDoorCode && passedRetinaScan {
|
||||
println("Welcome!")
|
||||
} else {
|
||||
println("ACCESS DENIED")
|
||||
}
|
||||
// 输出 "ACCESS DENIED"
|
||||
```
|
||||
|
||||
### 逻辑或
|
||||
逻辑或(`a || b`)是一个由两个连续的`|`组成的中置运算符。它表示了两个逻辑表达式的其中一个为`true`,整个表达式就为`true`。
|
||||
|
||||
同逻辑与运算类似,逻辑或也是"短路计算"的,当左端的表达式为`true`时,将不计算右边的表达式了,因为它不可能改变整个表达式的值了。
|
||||
|
||||
以下示例代码中,第一个布尔值(`hasDoorKey`)为`false`,但第二个值(`knowsOverridePassword`)为`true`,所以整个表达是`true`,于是允许进入:
|
||||
|
||||
```swift
|
||||
let hasDoorKey = false
|
||||
let knowsOverridePassword = true
|
||||
if hasDoorKey || knowsOverridePassword {
|
||||
println("Welcome!")
|
||||
} else {
|
||||
println("ACCESS DENIED")
|
||||
}
|
||||
// 输出 "Welcome!"
|
||||
```
|
||||
|
||||
### 组合逻辑
|
||||
|
||||
我们可以组合多个逻辑运算来表达一个复合逻辑:
|
||||
|
||||
```swift
|
||||
if enteredDoorCode && passedRetinaScan || hasDoorKey || knowsOverridePassword {
|
||||
println("Welcome!")
|
||||
} else {
|
||||
println("ACCESS DENIED")
|
||||
}
|
||||
// 输出 "Welcome!"
|
||||
```
|
||||
|
||||
这个例子使用了含多个`&&`和`||`的复合逻辑。但无论怎样,`&&`和`||`始终只能操作两个值。所以这实际是三个简单逻辑连续操作的结果。我们来解读一下:
|
||||
|
||||
如果我们输入了正确的密码并通过了视网膜扫描; 或者我们有一把有效的钥匙; 又或者我们知道紧急情况下重置的密码,我们就能把门打开进入。
|
||||
|
||||
前两种情况,我们都不满足,所以前两个简单逻辑的结果是`false`,但是我们是知道紧急情况下重置的密码的,所以整个复杂表达式的值还是`true`。
|
||||
|
||||
### 使用括号来明确优先级
|
||||
|
||||
为了一个复杂表达式更容易读懂,在合适的地方使用括号来明确优先级是很有效的,虽然它并非必要的。在上个关于门的权限的例子中,我们给第一个部分加个括号,使用它看起来逻辑更明确:
|
||||
|
||||
```swift
|
||||
if (enteredDoorCode && passedRetinaScan) || hasDoorKey || knowsOverridePassword {
|
||||
println("Welcome!")
|
||||
} else {
|
||||
println("ACCESS DENIED")
|
||||
}
|
||||
// 输出 "Welcome!"
|
||||
```
|
||||
|
||||
这括号使得前两个值被看成整个逻辑表达中独立的一个部分。虽然有括号和没括号的输出结果是一样的,但对于读代码的人来说有括号的代码更清晰。可读性比简洁性更重要,请在可以让你代码变清晰地地方加个括号吧!
|
||||
|
||||
826
source/chapter2/03_Strings_and_Characters.md
Normal file → Executable file
826
source/chapter2/03_Strings_and_Characters.md
Normal file → Executable file
@ -1,415 +1,411 @@
|
||||
# 字符串和字符 (Strings and Characters)
|
||||
|
||||
本页包含内容:
|
||||
|
||||
- 字符串字面量
|
||||
- 初始化空字符串
|
||||
- 字符串可变性
|
||||
- 字符串是值类型
|
||||
- 使用字符
|
||||
- 计算字符数量
|
||||
- 连接字符串和字符
|
||||
- 字符串插值
|
||||
- 比较字符串
|
||||
- 字符串大小写
|
||||
- Unicode
|
||||
|
||||
---
|
||||
|
||||
**String** 是例如 "hello, world", "海贼王" 这样的有序的 **Character** (字符) 类型的值的集合,通过 **String** 类型来表示。
|
||||
|
||||
Swift 的 **String** 和 **Character** 类型提供了一个快速的,兼容 Unicode 的方式来处理代码中的文本信息。
|
||||
创建和操作字符串的语法与 C 语言中字符串操作相似,轻量并且易读。
|
||||
字符串连接操作只需要简单地通过 `+` 号将两个字符串相连即可。
|
||||
与 Swift 中其他值一样,能否更改字符串的值,取决于其被定义为常量还是变量。
|
||||
|
||||
尽管语法简易,但 **String** 类型是一种快速、现代化的字符串实现。
|
||||
每一个字符串都是由独立编码的 Unicode 字符组成,并提供了以不同 Unicode 表示 (representations) 来访问这些字符的支持。
|
||||
|
||||
Swift可以在常量、变量、字面量和表达式中进行字符串插值操作,可以轻松创建用于展示、存储和打印的自定义字符串。
|
||||
|
||||
> 注意:
|
||||
>
|
||||
> Swift 的 **String** 类型与 Foundation NSString 类进行了无缝桥接。
|
||||
> 如果您利用 Cocoa 或 Cocoa Touch 中的 Foundation 框架进行工作。
|
||||
> 所有 **NSString** API 都可以调用您创建的任意 **String** 类型的值。
|
||||
> 除此之外,还可以使用本章介绍的 **String** 特性。
|
||||
> 您也可以在任意要求传入 **NSString** 实例作为参数的 API 中使用 **String** 类型的值作为替代。
|
||||
>
|
||||
>更多关于在 Foundation 和 Cocoa 中使用 **String** 的信息请查看 [Using Swift with Cocoa and Objective-C](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/index.html#//apple_ref/doc/uid/TP40014216)。
|
||||
|
||||
---
|
||||
|
||||
### 字符串字面量
|
||||
|
||||
您可以在您的代码中包含一段预定义的字符串值作为字符串字面量。
|
||||
字符串字面量是由双引号 ("") 包裹着的具有固定顺序的文本字符集。
|
||||
|
||||
字符串字面量可以用于为常量和变量提供初始值。
|
||||
|
||||
```
|
||||
let someString = "Some string literal value"
|
||||
```
|
||||
|
||||
> 注意:
|
||||
>
|
||||
> `someString` 变量通过字符串字面量进行初始化,Swift 因此推断该变量为 **String** 类型。
|
||||
|
||||
字符串字面量可以包含以下特殊字符:
|
||||
|
||||
* 转义字符 `\0` (空字符)、`\\`(反斜线)、`\t` (水平制表符)、`\n` (换行符)、`\r` (回车符)、`\"` (双引号)、`\'` (单引号)。
|
||||
* 单字节 Unicode 标量,写成 `\xnn`,其中 `nn` 为两位十六进制数。
|
||||
* 双字节 Unicode 标量,写成 `\unnnn`,其中 `nnnn` 为四位十六进制数。
|
||||
* 四字节 Unicode 标量,写成 `\Unnnnnnnn`,其中 `nnnnnnnn` 为八位十六进制数。
|
||||
|
||||
下面的代码为各种特殊字符的使用示例。
|
||||
`wiseWords` 常量包含了两个转移特殊字符 (双括号);
|
||||
`dollarSign`、`blackHeart` 和 `sparklingHeart` 常量演示了三种不同格式的 Unicode 标量:
|
||||
|
||||
```
|
||||
let wiseWords = "\"我是要成为海贼王的男人\" - 路飞"
|
||||
// "我是要成为海贼王的男人" - 路飞
|
||||
let dollarSign = "\x24" // $, Unicode 标量 U+0024
|
||||
let blackHeart = "\u2665" // ♥, Unicode 标量 U+2665
|
||||
let sparklingHeart = "\U0001F496" // 💖, Unicode 标量 U+1F496
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 初始化空字符串
|
||||
|
||||
为了构造一个很长的字符串,可以创建一个空字符串作为初始值。
|
||||
可以将空的字符串字面量赋值给变量,也可以初始化一个新的 **String** 实例:
|
||||
|
||||
```
|
||||
var emptyString = "" // 空字符串字面量
|
||||
var anotherEmptyString = String() // 初始化 String 实例
|
||||
// 两个字符串均为空并等价。
|
||||
```
|
||||
|
||||
您可以通过检查其 **Boolean** 类型的 `isEmpty` 属性来判断该字符串是否为空:
|
||||
|
||||
```
|
||||
if emptyString.isEmpty {
|
||||
println("什么都没有")
|
||||
}
|
||||
// 输出 "什么都没有"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 字符串可变性
|
||||
|
||||
您可以通过将一个特定字符串分配给一个变量来对其进行修改,或者分配给一个常量来保证其不会被修改:
|
||||
|
||||
```
|
||||
var variableString = "Horse"
|
||||
variableString += " and carriage"
|
||||
// variableString 现在为 "Horse and carriage"
|
||||
let constantString = "Highlander"
|
||||
constantString += " and another Highlander"
|
||||
// 这会报告一个编译错误 (compile-time error) - 常量不可以被修改。
|
||||
```
|
||||
|
||||
> 注意:
|
||||
>
|
||||
> 在 Objective-C 和 Cocoa 中,您通过选择两个不同的类( `NSString` 和 `NSMutableString` )来指定该字符串是否可以被修改,Swift 中的字符串是否可以修改仅通过定义的是变量还是常量来决定,实现了多种类型可变性操作的统一。
|
||||
|
||||
---
|
||||
|
||||
### 字符串是值类型
|
||||
|
||||
Swift 的 **String** 类型是值类型。
|
||||
如果您创建了一个新的字符串,那么当其进行常量、变量赋值操作或在函数/方法中传递时,会进行值拷贝。
|
||||
任何情况下,都会对已有字符串值创建新副本,并对该新副本进行传递或赋值操作。
|
||||
值类型在 [Structures and Enumerations Are Value Types](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/ClassesAndStructures.html#//apple_ref/doc/uid/TP40014097-CH13-XID_104) 中进行了说明。
|
||||
|
||||
> 注意:
|
||||
>
|
||||
> 与 Cocoa 中的 NSString 不同,当您在 Cocoa 中创建了一个 NSString 实例,并将其传递给一个函数/方法,或者赋值给一个变量,您传递或赋值的是该 NSString 实例的一个引用,除非您特别要求进行值拷贝,否则字符串不会生成新的副本来进行赋值操作。
|
||||
|
||||
Swift 默认字符串拷贝的方式保证了在函数/方法中传递的是字符串的值。
|
||||
很明显无论该值来自于哪里,都是您独自拥有的。
|
||||
您可以放心您传递的字符串本身不会被更改。
|
||||
|
||||
在实际编译时,Swift 编译器会优化字符串的使用,使实际的复制只发生在绝对必要的情况下,这意味着您将字符串作为值类型的同时可以获得极高的性能。
|
||||
|
||||
---
|
||||
|
||||
### 使用字符(Characters)
|
||||
|
||||
Swift 的 **String** 类型表示特定序列的 **Character** (字符) 类型值的集合。
|
||||
每一个字符值代表一个 Unicode 字符。
|
||||
您可利用 for-in 循环来遍历字符串中的每一个字符:
|
||||
|
||||
```
|
||||
for character in "Dog!🐶" {
|
||||
println(character)
|
||||
}
|
||||
// D
|
||||
// o
|
||||
// g
|
||||
// !
|
||||
// 🐶
|
||||
```
|
||||
|
||||
for-in 循环在[For Loops](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/ControlFlow.html#//apple_ref/doc/uid/TP40014097-CH9-XID_154)中进行了详细描述。
|
||||
|
||||
另外,通过标明一个 **Character** 类型注解并通过字符字面量进行赋值,可以建立一个独立的字符常量或变量:
|
||||
|
||||
```
|
||||
let yenSign: Character = "¥"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 计算字符数量
|
||||
|
||||
通过调用全局 `countElements` 函数,并将字符串作为参数进行传递,可以获取该字符串的字符数量。
|
||||
|
||||
```
|
||||
let unusualMenagerie = "Koala 🐨, Snail 🐌, Penguin 🐧, Dromedary 🐪"
|
||||
println("unusualMenagerie has \(countElements(unusualMenagerie)) characters")
|
||||
// prints "unusualMenagerie has 40 characters"
|
||||
```
|
||||
|
||||
> 注意:
|
||||
>
|
||||
> 不同的 Unicode 字符以及相同 Unicode 字符的不同表示方式可能需要不同数量的内存空间来存储。
|
||||
> 所以Swift 中的字符在一个字符串中并不一定占用相同的内存空间。
|
||||
> 因此字符串的长度不得不通过迭代字符串中每一个字符的长度来进行计算。
|
||||
> 如果您正在处理一个长字符串,需要注意 `countElements` 函数必须遍历字符串中的字符以精准计算字符串的长度。
|
||||
>
|
||||
> 另外需要注意的是通过 `countElements` 返回的字符数量并不总是与包含相同字符的 NSString 的 `length` 属性相同。
|
||||
> NSString 的 `length` 属性是基于利用 UTF-16 表示的十六位代码单元数字,而不是基于 Unicode 字符。
|
||||
> 为了解决这个问题,NSString 的 `length` 属性在被 Swift的 **String** 访问时会成为 `utf16count`。
|
||||
|
||||
---
|
||||
|
||||
### 连接字符串和字符
|
||||
|
||||
字符串和字符的值可以通过加法运算符 (`+`) 相加在一起并创建一个新的字符串值:
|
||||
|
||||
```
|
||||
let string1 = "hello"
|
||||
let string2 = " there"
|
||||
let character1: Character = "!"
|
||||
let character2: Character = "?"
|
||||
|
||||
let stringPlusCharacter = string1 + character1 // 等于 "hello!"
|
||||
let stringPlusString = string1 + string2 // 等于 "hello there"
|
||||
let characterPlusString = character1 + string1 // 等于 "!hello"
|
||||
let characterPlusCharacter = character1 + character2 // 等于 "!?"
|
||||
```
|
||||
|
||||
您也可以通过加法赋值运算符 (+=) 将一个字符串或者字符添加到一个已经存在字符串变量上:
|
||||
|
||||
```
|
||||
var instruction = "look over"
|
||||
instruction += string2
|
||||
// instruction 现在等于 "look over there"
|
||||
|
||||
var welcome = "good morning"
|
||||
welcome += character1
|
||||
// welcome 现在等于 "good morning!"
|
||||
```
|
||||
|
||||
>注意:
|
||||
>
|
||||
>您不能将一个字符串或者字符添加到一个已经存在的字符变量上,因为字符变量只能包含一个字符。
|
||||
|
||||
---
|
||||
|
||||
### 字符串插值
|
||||
|
||||
字符串插值是一种构建新字符串的方式,可以在其中包含常量、变量、字面量和表达式。
|
||||
您插入的字符串字面量的每一项都被包裹在以反斜线为前缀的圆括号中:
|
||||
|
||||
```
|
||||
let multiplier = 3
|
||||
let message = "\(multiplier) 乘以 2.5 是 \(Double(multiplier) * 2.5)"
|
||||
// message is "3 乘以 2.5 是 7.5"
|
||||
```
|
||||
|
||||
在上面的例子中,`multiplier` 作为 `\(multiplier)` 被插入到一个字符串字面量中。
|
||||
当创建字符串执行插值计算时此占位符会被替换为 `multiplier` 实际的值。
|
||||
|
||||
`multiplier` 的值也作为字符串中后面表达式的一部分。
|
||||
该表达式计算 `Double(multiplier) * 2.5` 的值并将结果 (7.5) 插入到字符串中。
|
||||
在这个例子中,表达式写为 `\(Double(multiplier) * 2.5)` 并包含在字符串字面量中。
|
||||
|
||||
>注意:
|
||||
>
|
||||
>您插值字符串中写在括号中的表达式不能包含非转义双引号 (`"`) 和反斜杠 (`\`),并且不能包含回车或换行符。
|
||||
|
||||
---
|
||||
|
||||
### 比较字符串
|
||||
|
||||
Swift 提供了三种方式来比较字符串的值:字符串相等,前缀相等和后缀相等。
|
||||
|
||||
##### 字符串相等
|
||||
|
||||
如果两个字符串以同一顺序包含完全相同的字符,则认为两者字符串相等:
|
||||
|
||||
```
|
||||
let quotation = "我们是一样一样滴."
|
||||
let sameQuotation = "我们是一样一样滴."
|
||||
if quotation == sameQuotation {
|
||||
println("这两个字符串被认为是相同的")
|
||||
}
|
||||
// prints "这两个字符串被认为是相同的"
|
||||
```
|
||||
|
||||
##### 前缀/后缀相等
|
||||
|
||||
通过调用字符串的 `hasPrefix`/`hasSuffix` 方法来检查字符串是否拥有特定前缀/后缀。
|
||||
两个方法均需要以字符串作为参数传入并传出 **Boolean** 值。
|
||||
两个方法均执行基本字符串和前缀/后缀字符串之间逐个字符的比较操作。
|
||||
|
||||
下面的例子以一个字符串数组表示莎士比亚话剧 `罗密欧与朱丽叶` 中前两场的场景位置:
|
||||
|
||||
```
|
||||
let romeoAndJuliet = [
|
||||
"Act 1 Scene 1: Verona, A public place",
|
||||
"Act 1 Scene 2: Capulet's mansion",
|
||||
"Act 1 Scene 3: A room in Capulet's mansion",
|
||||
"Act 1 Scene 4: A street outside Capulet's mansion",
|
||||
"Act 1 Scene 5: The Great Hall in Capulet's mansion",
|
||||
"Act 2 Scene 1: Outside Capulet's mansion",
|
||||
"Act 2 Scene 2: Capulet's orchard",
|
||||
"Act 2 Scene 3: Outside Friar Lawrence's cell",
|
||||
"Act 2 Scene 4: A street in Verona",
|
||||
"Act 2 Scene 5: Capulet's mansion",
|
||||
"Act 2 Scene 6: Friar Lawrence's cell"
|
||||
]
|
||||
```
|
||||
|
||||
您可以利用 `hasPrefix` 方法来计算话剧中第一幕的场景数:
|
||||
|
||||
```
|
||||
var act1SceneCount = 0
|
||||
for scene in romeoAndJuliet {
|
||||
if scene.hasPrefix("Act 1 ") {
|
||||
++act1SceneCount
|
||||
}
|
||||
}
|
||||
println("There are \(act1SceneCount) scenes in Act 1")
|
||||
// prints "There are 5 scenes in Act 1"
|
||||
```
|
||||
|
||||
##### 大写和小写字符串
|
||||
|
||||
您可以通过字符串的 `uppercaseString` 和 `lowercaseString` 属性来访问大写/小写版本的字符串。
|
||||
|
||||
```
|
||||
let normal = "Could you help me, please?"
|
||||
let shouty = normal.uppercaseString
|
||||
// shouty 值为 "COULD YOU HELP ME, PLEASE?"
|
||||
let whispered = normal.lowercaseString
|
||||
// whispered 值为 "could you help me, please?"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Unicode
|
||||
|
||||
Unicode 是一个国际标准,用于文本的编码和表示。
|
||||
它使您可以用标准格式表示来自任意语言几乎所有的字符,并能够对文本文件或网页这样的外部资源中的字符进行读写操作。
|
||||
|
||||
Swift 的字符串和字符类型是完全兼容 Unicode 标准的,它支持如下所述的一系列不同的 Unicode 编码。
|
||||
|
||||
###### Unicode 术语(Terminology)
|
||||
|
||||
Unicode 中每一个字符都可以被解释为一个或多个 unicode 标量。
|
||||
字符的 unicode 标量是一个唯一的21位数字(和名称),例如 `U+0061` 表示小写的拉丁字母A ("a"),`U+1F425` 表示小幺鸡表情 ("🐥")
|
||||
|
||||
当 Unicode 字符串被写进文本文件或其他存储结构当中,这些 unicode 标量将会按照 Unicode 定义的集中格式之一进行编码。其包括 `UTF-8` (以8位代码单元进行编码) 和 `UTF-16` (以16位代码单元进行编码)。
|
||||
|
||||
##### 字符串的 Unicode 表示
|
||||
|
||||
Swift 提供了几种不同的方式来访问字符串的 Unicode 表示。
|
||||
|
||||
您可以利用 `for-in` 来对字符串进行遍历,从而以 Unicode 字符的方式访问每一个字符值。
|
||||
该过程在 [Working with Characters](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html#//apple_ref/doc/uid/TP40014097-CH7-XID_376) 中进行了描述。
|
||||
|
||||
另外,能够以其他三种 Unicode 兼容的方式访问字符串的值:
|
||||
|
||||
* UTF-8 代码单元集合 (利用字符串的 `utf8` 属性进行访问)
|
||||
* UTF-16 代码单元集合 (利用字符串的 `utf16` 属性进行访问)
|
||||
* 21位的 Unicode 标量值集合 (利用字符串的 `unicodeScalars` 属性进行访问)
|
||||
|
||||
下面由 `D` `o` `g` `!` 和 `🐶` (`DOG FACE`,Unicode 标量为 `U+1F436`)组成的字符串中的每一个字符代表着一种不同的表示:
|
||||
|
||||
```
|
||||
let dogString = "Dog!🐶"
|
||||
```
|
||||
|
||||
##### UTF-8
|
||||
|
||||
您可以通过遍历字符串的 `utf8` 属性来访问它的 `UTF-8` 表示。
|
||||
其为 **UTF8View** 类型的属性,**UTF8View** 是无符号8位 (`UInt8`) 值的集合,每一个 `UInt8` 值都是一个字符的 UTF-8 表示:
|
||||
|
||||
```
|
||||
for codeUnit in dogString.utf8 {
|
||||
print("\(codeUnit) ")
|
||||
}
|
||||
print("\n")
|
||||
// 68 111 103 33 240 159 144 182
|
||||
```
|
||||
|
||||
上面的例子中,前四个10进制代码单元值 (68, 111, 103, 33) 代表了字符 `D` `o` `g` 和 `!` ,他们的 UTF-8 表示与 ASCII 表示相同。
|
||||
后四个代码单元值 (240, 159, 144, 182) 是 `DOG FACE` 的4位 UTF-8 表示。
|
||||
|
||||
##### UTF-16
|
||||
|
||||
您可以通过遍历字符串的 `utf16` 属性来访问它的 `UTF-16` 表示。
|
||||
其为 **UTF16View** 类型的属性,**UTF16View** 是无符号16位 (`UInt16`) 值的集合,每一个 `UInt16` 都是一个字符的 UTF-16 表示:
|
||||
|
||||
```
|
||||
for codeUnit in dogString.utf16 {
|
||||
print("\(codeUnit) ")
|
||||
}
|
||||
print("\n")
|
||||
// 68 111 103 33 55357 56374
|
||||
```
|
||||
|
||||
同样,前四个代码单元值 (68, 111, 103, 33) 代表了字符 `D` `o` `g` 和 `!` ,他们的 UTF-16 代码单元和 UTF-8 完全相同。
|
||||
|
||||
第五和第六个代码单元值 (55357 and 56374) 是 `DOG FACE` 字符的UTF-16 表示。
|
||||
第一个值为 `U+D83D` (十进制值为 55357),第二个值为 `U+DC36` (十进制值为 56374)。
|
||||
|
||||
##### Unicode 标量 (Scalars)
|
||||
|
||||
您可以通过遍历字符串的 `unicodeScalars` 属性来访问它的 Unicode 标量表示。
|
||||
其为 **UnicodeScalarView** 类型的属性, **UnicodeScalarView** 是 `UnicodeScalar` 的集合。
|
||||
`UnicodeScalar` 是21位的 Unicode 代码点。
|
||||
|
||||
每一个 `UnicodeScalar` 拥有一个值属性,可以返回对应的21位数值,用 `UInt32` 来表示。
|
||||
|
||||
```
|
||||
for scalar in dogString.unicodeScalars {
|
||||
print("\(scalar.value) ")
|
||||
}
|
||||
print("\n")
|
||||
// 68 111 103 33 128054
|
||||
```
|
||||
|
||||
同样,前四个代码单元值 (68, 111, 103, 33) 代表了字符 `D` `o` `g` 和 `!` 。
|
||||
第五位数值,128054,是一个十六进制1F436的十进制表示。
|
||||
其等同于 `DOG FACE` 的Unicode 标量 U+1F436。
|
||||
|
||||
作为查询字符值属性的一种替代方法,每个 `UnicodeScalar` 值也可以用来构建一个新的字符串值,比如在字符串插值中使用:
|
||||
|
||||
```
|
||||
for scalar in dogString.unicodeScalars {
|
||||
println("\(scalar) ")
|
||||
}
|
||||
// D
|
||||
// o
|
||||
// g
|
||||
// !
|
||||
// 🐶
|
||||
```
|
||||
|
||||
| ||||