把《编程珠玑》读薄

Standard
August 11, 2013
作者:Hawstein
出处:http://hawstein.com/posts/make-thiner-programming-pearls.html
声明:本文采用以下协议进行授权: 自由转载-非商用-非衍生-保持署名|Creative Commons BY-NC-ND 3.0 ,转载请注明作者及出处。

目录

  1. 开篇
  2. 啊哈!算法
  3. 数据决定程序结构
  4. 编写正确的程序
  5. 编程中的次要问题
  6. 程序性能分析
  7. 粗略估算
  8. 算法设计技术
  9. 代码调优
  10. 节省空间
  11. 排序
  12. 取样问题
  13. 搜索
  14. 字符串

开篇

具体化你的解决的问题。下面是A和B的对话。

A:我该如何对磁盘文件进行排序?
B:需要排序的内容是什么?文件中有多少条记录?每个记录的格式是什么?
A:该文件包含至多10,000,000个记录,每条记录都是一个7位整数。
B:如果文件那么小,为什么要使用磁盘排序呢?为什么不在主存中对它排序?
A:该功能是某大型系统中的一部分,大概只能提供1MB主存给它。
B:你能将记录方面的内容说得更详细一些吗?
A:每个记录是一个7位正整数,没有其它的关联数据,每个整数至多只能出现一次。
... ...

经过一系统的问题,我们可以将一个定义模糊不清的问题变得具体而清晰:

输入:
所输入的是一个文件,至多包含n个正整数,每个正整数都要小于n,这里n=10^7。
如果输入时某一个整数出现了两次,就会产生一个致命的错误。
这些整数与其它任何数据都不关联。
输出:
以增序形式输出经过排序的整数列表。
约束:
大概有1MB的可用主存,但可用磁盘空间充足。运行时间至多允许几分钟,
10秒钟是最适宜的运行时间。

如果主存容量不是严苛地限制在1MB,比如说可以是1MB多,或是1~2MB之间, 那么我们就可以一次性将所有数据都加载到主存中,用Bitmap来做。 10,000,000个数就需要10,000,000位,也就是10,000,000b = 1.25MB。

程序可分为三个部分:第一,初始化所有的位为0;第二,读取文件中每个整数, 如果该整数对应的位已经为1,说明前面已经出现过这个整数,抛出异常,退出程序 (输入要求每个整数都只能出现一次)。否则,将相应的位置1;第三, 检查每个位,如果某个位是1,就写出相应的整数,从而创建已排序的输出文件。

如果主存容量严苛地限制在1MB,而使用Bitmap需要1.25MB, 因此无法一次载入完成排序。那么,我们可以将该文件分割成两个文件, 再分别用Bitmap处理。分割策略可以简单地把前一半的数据放到一个文件, 后一半的数据放到另一个文件,分别排序后再做归并。 也可以把文件中小于某个数(比如5,000,000)的整数放到一个文件,叫less.txt, 把其余的整数放到另一个文件,叫greater.txt。分别排序后, 把greater.txt的排序结果追加到less.txt的排序结果即可。

啊哈!算法

第2章围绕3个问题展开。

  • 给定一个包含32位整数的顺序文件,它至多只能包含40亿个这样的整数, 并且整数的次序是随机的。请查找一个此文件中不存在的32位整数。 在有足够主存的情况下,你会如何解决这个问题? 如果你可以使用若干外部临时文件,但可用主存却只有上百字节, 你会如何解决这个问题?

这是CTCI中的一道题目,详细解答请戳以下链接:

请猛戳我

  • 请将一个具有n个元素的一维向量向左旋转i个位置。例如,假设n=8,i=3, 那么向量abcdefgh旋转之后得到向量defghabc。

这个问题很常见了,做3次翻转即可,无需额外空间:

reverse(0, i-1); // cbadefgh
reverse(i, n-1); // cbahgfed
reverse(0, n-1); // defghabc
  • 给定一本英语单词词典,请找出所有的变位词集。例如,因为“pots”, “stop”,“tops”相互之间都是由另一个词的各个字母改变序列而构成的, 因此这些词相互之间就是变位词。

这个问题可以分3步来解决。第一步将每个单词按字典序排序, 做为原单词的签名,这样一来,变位词就会具有相同的签名。 第二步对所有的单词按照其签名进行排序,这样一来,变位词就会聚集到一起。 第三步将变位词分组,形成变位词集。示意图如下:

数据决定程序结构

恰当的数据视图实际上决定了程序的结构。 我们常常可以通过重新组织内部数据来使程序变得小而美。

发明家悖论:更一般性的问题也许更容易解决。(有时候吧)

程序员在节省空间方面无计可施时,将自己从代码中解脱出来, 退回起点并集中心力研究数据,常常能有奇效。数据的表示形式是程序设计的根本。

下面是退回起点进行思考时的几条原则:

  • 使用数组重新编写重复代码。冗长的相似代码常常可以使用最简单的数据结构—— 数组来更好地表述。
  • 封装复杂结构。当需要非常复杂的数据结构时,使用抽象术语进行定义, 并将操作表示为类。
  • 尽可能使用高级工具。超文本,名字-值对,电子表格,数据库, 编程语言等都是特定问题领域中的强大的工具。
  • 从数据得出程序的结构。在动手编写代码之前,优秀的程序员会彻底理解输入, 输出和中间数据结构,并围绕这些结构创建程序。

提到的书籍:Polya的《How to Solve it》,中文书《怎样解题》; Kernighan和Plauger的《Elements of Programming Style》;Fred Brooks的《人月神话》 Steve McConnell的《代码大全》;《Rapid Development》; 《Software Project Survival Guide》

编写正确的程序

本章以二分搜索为例子,讲述了如何对程序进行验证及正确性分析。

深入阅读:David Gries的《Science of Programming》 是程序验证领域里极佳的一本入门书籍。

编程中的次要问题

到目前为止,你已经做了一切该做的事:通过深入挖掘定义了正确的问题, 通过仔细选择算法和数据结构平衡了真正的需求,通过程序验证技术写出了优雅的代码, 并且对其正确性相当有把握。万事俱备,只欠编程。

  • 使用断言assert
  • 自动化测试程序

进阶阅读:《Practice of Programming》第5章(调试),第6章(测试) 《Code Complete》第25章(单元测试),第26章(调试)

程序性能分析

下图展示了一个程序的性能提升过程, 该程序的作用是对三维空间中n个物体的运动进行仿真。从图中可以看出, 一个程序可以从多方面进行性能提升,而其中算法和数据结构的选择又显得尤为重要。

从设计层面提升程序性能:

  1. 问题定义。良好的问题定义可以有效减少程序运行时间和程序长度。
  2. 系统结构。将大型系统分解成模块,也许是决定其性能的最重要的单个因素。
  3. 算法和数据结构。这个不用说了。
  4. 代码调优。针对代码本身的改进。
  5. 系统软件。有时候改变系统所基于的软件比改变系统本身更容易。
  6. 硬件。更快的硬件可以提高系统的性能。

深入阅读:Butler Lampson的“Hints for Computer System Design”, 该论文特别适合于集成硬件和软件的计算机系统设计。

粗略估算

这一章讲述了估算技术,我认为是相当有用的一章。

文中先抛出一个问题:密西西比河一天流出多少水?如果让你来回答, 你会怎么答,注意不能去Google哦。

作者是这么回答这个问题:假设河的出口大约有1英里宽和20英尺深(1/250英里), 而河水的流速是每小时5英里,也就是每天120英里。则可以计算出一天的流量:

1英里 * 1/250英里 * 120英里/天  约等于  1/2 英里^3/天

上述算式非常简单,可是在看到这些文字之前,如果有人真的问你, 密西西比河一天流出多少水?你真的能答上来吗?还是愣了一下后,摆摆手,说: 这我哪知道!

对于上面的问题,我们至少可以注意到以下两点:

  1. 你需要把问题转换成一个可计算的具体模型。这一点往往不需要太担心, 因为我们做的是估算,所以可以忽视很多无关紧要的因素,可以去简化你的模型, 记住我们要的只是一个粗略计算的结果。比如对于上面的问题, 计算密西西比河一天流出多少水其实就是计算其一天的流量,利用中学所学知识, 流量 = 截面积 x 流速,那我们就只需计算密西西比河的出水口的截面积和流速即可。 我们可以将出水口简化成一个矩形,因此就只需要知道出水口的宽和深即可。
  2. 你需要知道常识性的东西。上面我们已经把问题转换成了一个可计算的具体模型: 流量 = 出水口宽 x 出水口深 x 流速。接下来呢?你需要代入具体的数值去求得答案。 而这就需要你具备一些常识性的知识了。比如作者就估计了密西西比河的出口有1英里宽, 20英尺深(如果你估计只有几十米宽,那就相差得太离谱了)。 这些常识性的知识比第1点更值得关注,因为你无法给出一个靠谱的估算值往往是因为这点。

当我们懂得如何把一个问题具体化定义出来并为其选用适当的模型, 并且我们也积累了必要的常识性的知识后,回答那些初看起来无从下手的问题也就不难了。 这就是估算的力量。

以下是估算时的一些有用提示:

  • 两个答案比一个答案好。即鼓励你从多个角度去对一个问题进行估算, 如果从不同角度得到的答案差别都不大,说明这个估算值是比较靠谱的。
  • 快速检验。即量纲检验。即等式两边最终的量纲要一致。 这一点在等式简单的时候相当显而易见。比如位移的单位是米,时间单位是秒, 速度单位是米/秒,那显然我们应该要用位移去除以时间来得到速度, 这样才能保证它们单位的一致。你可能会说,我了个去,这种小学生都懂的事, 你好意思拿出来讲。其实不然,当你面对的是一个具有多个变量的复杂物理公式, 或者你提出某种物理假设,正在考虑将其公式化,该方法可以切切实实地帮你做出检验。
  • 经验法则。“72法则”:1.假设以年利率r%投资一笔钱y年,如果r*y = 72, 那么你的投资差不多会翻倍。2.如果一个盘子里的菌群以每小时3%的速率增长, 那么其数量每天(24小时)都会翻倍。在误差不超过千分之五的情况下, \pi秒就是一个纳世纪。也就是说:

    3.14秒 = 10-9 * 100年 = 10-7 年

也就是说,1年大概是3.14×107 秒。所以如果有人告诉你,一个程序运行107 秒, 你应该能很快反应出,他说的其实是4个月。

  • 实践。与许多其他活动一样,估算技巧只能通过实践来提高。

如果问题的规模太大,我们还可以通过求解它的小规模同质问题来做估算。比如, 我们想测试某个程序运行10亿次需要多长时间,如果你真去跑10亿次, 说不定运行几个小时都没结束,那不是很悲剧?我们可以运行这个程序1万次或是10万次, 得出结果然后倍增它即可。当然,这个结果未必是准确的, 因为你没法保证运行时间是随着运行次数线性增加的。谨慎起见,我们可以运行不同的次数, 来观察它的变化趋势。比如运行10次,100次,1000次,10000次等, 观察它的运行时间是否是线性增加的,或是一条二次曲线。

有时候,我们需要为估算的结果乘上一个安全系数。比如, 我们预估完成某项功能需要时间t,那根据以往经验,也许我们需要为这个值乘上2或4, 这样也许才是一个靠谱的预估值。

Little定律:系统中物体的平均数量等于物体离开系统的平均速率和每个物体在系统中停留 的平均时间的乘积。(如果物体离开和进入系统的总体出入流是平衡的, 那么离开速率也就是进入速率)

举个例子,比如你正在排除等待进入一个火爆的夜总会, 你可以通过估计人们进入的速率来了解自己还要等待多长时间。根据Little定律, 你可以推论:这个地方可以容纳约60人,每个人在里面逗留时间大约是3小时, 因此我们进入夜总会的速率大概是每小时20人。现在队伍中我们前面还有20人, 也就意味着我们还要等待大约一个小时。

深入阅读:Darrell Huff的《How To Lie With Statistics》;关键词: 费米近似(Fermi estimate, Fermi problem)

算法设计技术

这一章就一个小问题研究了4种不同的算法,重点强调这些算法的设计技术。 研究的这个小问题是一个非常常见的面试题:子数组之和的最大值。 如果之前没有听过,建议Google之。

深入阅读:Aho,Hopcroft和Ullman的《Data Structures and Algorithms》 Cormen,Leiserson,Rivest和Stein的《Introduction to Algorithms》

代码调优

前面各章讨论了提高程序效率的高层次方法:问题定义,系统结构, 算法设计及数据结构选择。本章讨论的则是低层次的方法:代码调优。

代码调优的最重要原理就是尽量少用它。不成熟的优化是大量编程灾害的根源。 它会危及程序的正确性,功能性以及可维护性。当效率很重要时, 第一步就是对系统进行性能监视,以确定其运行时间的分布状况。 效率问题可以由多种方法来解决,只有在确信没有更好的解决方案时才考虑进行代码调优。

事实上,如果不是十分十分必要,不要去做代码调优, 因为它会牺牲掉软件的其他许多性质。

so,just skip this chapter。

节省空间

本章讲述了节省空间的一些重要方法。

减少程序所需数据的存储空间,一般有以下方法:

  • 不存储,重新计算。
  • 稀疏数据结构。下面着重讲一下这点。
  • 数据压缩。可以通过压缩的方式对对象进行编码,以减少存储空间。
  • 分配策略。只有在需要的时候才进行分配。
  • 垃圾回收。对废弃的存储空间进行回收再利用。

以下是节省代码空间的几种通用技术:

  • 函数定义。用函数替换代码中的常见模式可以简化程序,同时减少代码的空间需求。
  • 解释程序。用解释程序命令替换长的程序文本。
  • 翻译成机器语言。可以将大型系统中的关键部分用汇编语言进行手工编码。

稀疏数据结构

假设我们有一个200 x 200的矩阵(共40000个元素),里面只有2000个元素有值, 其它的都为0,示意图如下:

显然这是一个稀疏矩阵,直接用一个200 x 200 的二维数组来存储这些数据会造成大量的空间浪费,共需要200x200x4B=160KB。 所以,我们应该想办法用另一种形式来存储这些数据。

方法一

使用数组表示所有的列,同时使用链表来表示给定列中的活跃元素。 如下图所示:

该结构中,有200个指针(colhead)和2000条记录(每条记录是两个整数和一个指针), 占用空间是200x4B + 2000x12B = 24800B = 24.8KB, 比直接用二维数组存储(160KB)要小很多。

方法二

我们可以开三个数组来保存这些数,如下图所示:

firstincol是一个长度为201的数组,对于第i列,在数组row中, 下标为firstincol[i]到firstincol[i+1]-1对应的行元素非0, 其值存储在相应的pointnum数组中。

比如对于上图,在第0列中,元素值非0的行有3行,分别是row[0],row[1],row[2], 元素值是pointnum[0],pointnum[1],pointnum[2];在第1列中,元素值非0的行有2行, 分别是row[3],row[4],元素值是pointnum[3],pointnum[4]。依次类推。

该结构所需要的存储空间为2x2000x4B + 201x4B = 16804B = 16.8KB。 由于row数组中的元素全部都小于200,所以每个元素可以用一个unsigned char来保存, firstincol数组中元素最大也就2000,所以可以用一个short(或unsigned short)来保存, pointnum中的元素是一个4B的int, 最终所需空间变为:2000x4B + 2000x1B + 201x2B = 10402B = 10.4KB。

深入阅读:Fred Brooks的《人月神话》

排序

本章先简单介绍了插入排序,然后着重讲述快速排序。

插入排序

// 版本1
void InsertSort(int a[], int n) {
    for(int i=1; i<n; ++i)
        for(int j=i; j>0 && a[j-1]>a[j]; --j)
            swap(a[j-1], a[j]);
}
// 版本2
void InsertSort1(int a[], int n) {
    for(int i=1; i<n; ++i) {
        int t = a[i];
        int j = i;
        for(; j>0 && a[j-1]>t; --j)
            a[j] = a[j-1];
        a[j] = t;
    }
}

快速排序

我们在这里规定:小于等于pivot的元素移到左边,大于pivot的元素移到右边。

实现1:单向移动版本

这个版本的关键是设置一快一慢两个指针,慢指针左侧都是小于等于pivot(包含慢指针所在位置), 慢指针到快指针之间的值是大于pivot,快指针右侧的值是还未比较过的。示意图如下:

小于等于pivot    |    大于pivot    |    ?
             slow                fast

快指针一次一步向前走,遇到大于pivot什么也不做继续向前走。遇到小于等于pivot的元素, 则慢指针slow向前走一步,然后交换快慢指针指向的元素。一次划分结束后, 再递归对左右两侧的元素进行快排。代码如下:

// 数组快排
void QSort(int a[], int head, int end) {
    if(a==NULL || head==end) return;
    int slow = head, fast = head + 1;
    int pivot = a[head];
    while(fast != end) {
        if(a[fast] <= pivot)
            swap(a[++slow], a[fast]);
        ++fast;
    }
    swap(a[head], a[slow]);
    QSort(a, head, slow);
    QSort(a, slow+1, end);
}

排序数组a只需要调用QSort(a, 0, n)即可。该思路同样可以很容易地在链表上实现:

// 单链表快排
void qsort(Node *head, Node *end){
    if(head==NULL || head==end) return;
    Node *slow = head, *fast = head->next;
    int pivot = head->data;
    while(fast != end){
        if(fast->data <= pivot){
            slow = slow->next;
            swap(slow->data, fast->data);
        }
        fast = fast->next;
    }
    swap(head->data, slow->data);
    qsort(head, slow);
    qsort(slow->next, end);
}

排序头指针为head的单链表只需调用qsort(head, NULL)即可。

实现2:双向移动版本

版本1能能够快速完成对随机整数数组的排序,但如果数组有序, 或是数组中元素相同,快排的时间复杂度会退化成O(n2 ),性能变得非常差。

一种缓解方案是使用双向移动版本的快排,它每次划分也是使用两个指针, 不过一个是从左向右移动,一个是从右向左移动,示意图如下:

小于等于pivot    |    ?    |    大于pivot
               i            j

指针j不断向左移动,直到遇到小于等于pivot,就交换指针i和j所指元素 (指针i一开始指向pivot);指针i不断向右移动,直到遇到大于pivot的, 就交换指针i和j所指元素。pivot在这个过程中,不断地换来换去, 最终会停在分界线上,分界线左边都是小于等于它的元素,右边都是大于它的元素。 这样就避免了最后还要交换一次pivot的操作,代码也变得美观许多。

int partition(int a[], int low, int high){
    int pivot = a[low], i=low, j=high;
    while(i < j){
        while(i<j && a[j]>pivot) --j;
        if(i < j) swap(a[i], a[j]);
        while(i<j && a[i]<=pivot) ++i;
        if(i < j) swap(a[i], a[j]);
    }
    return i;
}
void quicksort(int a[], int first, int last){
    if(first<last){
        int k = partition(a, first, last);
        quicksort(a, first, k-1);
        quicksort(a, k+1, last);
    }
}

当然,如果对于partition函数,你如果觉得大循环内的两个swap还是做了些无用功的话, 也可以把pivot的赋值放到最后一步,而不是在这个过程中swap来swap去的。代码如下:

int partition(int a[], int low, int high){
    int pivot = a[low], i=low, j=high;
    while(i<j){
        while(i<j && a[j]>pivot) --j;
        if(i<j) a[i++] = a[j];
        while(i<j && a[i]<=pivot) ++i;
        if(i<j) a[j--] = a[i];
    }
    a[i] = pivot;
    return i;
}

如果数组基本有序,那随机选择pivot(而不像上面那样选择第一个做为pivot) 会得到更好的性能。在partition函数里,我们只需要在数组中随机选一个元素, 然后将它和数组中第一个元素交换,后面的划分代码无需改变, 就可以达到随机选择pivot的效果。

进一步优化

对于小数组,用插入排序之类的简单方法来排序反而会更快,因此在快排中, 当数组长度小于某个值时,我们就什么也不做。对应到代码中, 就是修改quicksort中的if条件:

if(first < last)  改为  if(last-first > cutoff)

其中cutoff是一个小整数。程序结束时,数组并不是有序的, 而是被组合成一块一块随机排列的值,并且满足这样的条件: 某一块中的元素小于它右边任何块中的元素。我们必须通过另一种排序算法对块内进行排序。 由于数组是几乎有序的,因此插入排序比较适用。

这种方法结合了快排和插入排序,让它们去做各自擅长的事情,往往比单纯用快排要快。

深入阅读:Don Knuth的《The Art of Computer Programming, Volume 3: Sorting and Searching》;Robert Sedgewick的《Algorithms》; 《Algorithms in C》,《Algorithms in C++》,《Algorithms in Java》。

取样问题

本章讲述了一个小的随机抽样问题,并用不同的方法来解决它。

问题:对于整数m和n,其中m<n,输出0~n-1范围内m个随机整数的有序列表, 不允许重复。

比如m=3, n=5,那么一种可能输出是0,2,3(要求有序)。实现1来自Knuth的TAOCP, 时间复杂度O(n):

void GenKnuth(int m, int n) {
    for(int i=0; i<n; ++i) {
        if((bigrand()%(n-i)) < m) {
            cout<<i<<endl;
            --m;
        }
    }
}

其中,bigrand()的作用是返回一个很大的随机整数。

实现2:在一个初始为空的集合里面插入随机整数,直到个数足够。代码如下:

void GenSets(int m, int n) {
    set<int> s;
    while(s.size() < m)
        s.insert(bigrand() % n);
    set<int>::iterator i;
    for(i=s.begin(); i!=s.end(); ++i)
        cout<<*i<<endl;
}

实现3:把包含整数0~n-1的数组顺序打乱,然后把前m个元素排序输出。 该方法的性能通常不如Knuth的算法。代码如下:

void GenShuf(int m, int n) {
    int x[n];
    for(int i=0; i<n; ++i)
        x[i] = i;
    for(int i=0; i<m; ++i) {
        int j = randint(i, n-1);
        swap(x[i], x[j]);
    }
    sort(x, x+m);
    for(int i=0; i<m; ++i)
        cout<<x[i]<<endl;
}

深入阅读:Don Knuth的《The Art of Computer Programming, Volume 2: Seminumerical Algorithms》

搜索

本章详细研究这样一个搜索问题:在没有其他相关数据的情况下,如何存储一组整数? 为些介绍了5种数据结构:有序数组,有序链表,二叉搜索树,箱,位向量。

其中,二叉搜索树应该熟练掌握,以下是一种实现:

struct Node {
    int data;
    Node *lchild, *rchild, *parent;
    Node(): lchild(NULL), rchild(NULL), parent(NULL) { }
};

class BST {
private:
    static const int kMax = 1000;
    Node *root_, *parent_, nodes_[kMax];
    int size_;

private:
    Node* minimum(Node* node);
    Node* maximum(Node* node);
    Node* successor(Node* node);
    Node* predecessor(Node* node);
    void Insert(Node* &node, int x);
    void InorderTraver(Node* node);
    Node* Find(Node* node, int x);
    
public:
    BST(): root_(NULL), parent_(NULL), size_(0) {
        memset(nodes_, '\0', sizeof(nodes_));
    }
    void Insert(int x);
    void InorderTraver();
    Node* Find(int x);
    void Remove(Node* z);
};

Node* BST::minimum(Node* node) {
    if(node == NULL) return NULL;
    while(node->lchild)
        node = node->lchild;
    return node;
}

Node* BST::maximum(Node* node) {
    if(node == NULL) return NULL;
    while(node->rchild)
        node = node->rchild;
    return node;
}

Node* BST::successor(Node* node) {
    if(node->rchild)
        return minimum(node->rchild);
    Node *y = node->parent;
    while(y && node==y->rchild) {
        node = y;
        y = node->parent;
    }
    return y;
}

Node* BST::predecessor(Node* node) {
    if(node->lchild)
        return maximum(node->lchild);
    Node *y = node->parent;
    while(y && node==y->lchild) {
        node = y;
        y = node->parent;
    }
    return y;
}

void BST::Insert(Node* &node, int x) {
    if(node == NULL) {
        nodes_[size_].data = x;
        nodes_[size_].parent = parent_;
        node = &nodes_[size_];
        ++size_;
        return;
    }
    parent_ = node;
    if(x < node->data)
        Insert(node->lchild, x);
    else
        Insert(node->rchild, x);
}

void BST::Insert(int x) {
    Insert(root_, x);
}

void BST::InorderTraver(Node* node) {
    if(node == NULL) return;
    InorderTraver(node->lchild);
    cout<<node->data<<" ";
    InorderTraver(node->rchild);
}

void BST::InorderTraver() {
    InorderTraver(root_);
}

Node* BST::Find(Node* node, int x) {
    if(node == NULL) return NULL;
    if(x < node->data) return Find(node->lchild, x);
    else if(x > node->data) return Find(node->rchild, x);
    else return node;
}

Node* BST::Find(int x) {
    return Find(root_, x);
}

void BST::Remove(Node* z) {
    if(!z->lchild && !z->rchild) {
        if(z == root_) root_ = NULL;
        else if(z == z->parent->lchild)
            z->parent->lchild = NULL;
        else
            z->parent->rchild = NULL;
    }

    else if(z->lchild==NULL || z->rchild==NULL) {
        if(z == root_) {
            if(z->lchild) root_ = z->lchild;
            else root_ = z->rchild;
            root_->parent = NULL;
        }
        else {
            if(z==z->parent->lchild && z->lchild) {
                z->parent->lchild = z->lchild;
                z->lchild->parent = z->parent;
            }
            else if(z==z->parent->lchild && z->rchild) {
                z->parent->lchild = z->rchild;
                z->rchild->parent = z->parent;
            }
            else if(z==z->parent->rchild && z->lchild) {
                z->parent->rchild = z->lchild;
                z->lchild->parent = z->parent;
            }
            else {
                z->parent->rchild = z->rchild;
                z->rchild->parent = z->parent;
            }
        }
    }

    else {
        Node *s = predecessor(z);
        z->data = s->data;
        if(z == s->parent)
            s->parent->lchild = s->lchild;
        else
            s->parent->rchild = s->lchild;

        if(s->lchild)
            s->lchild->parent = s->parent;
    }
}

本章主要介绍堆,下面是关于堆的一些主要操作:

// 最大堆实现, 数组下标从1开始,a[0]不使用。

// 交换两数
void swap(int &a, int &b) {
    int t = a;
    a = b;
    b = t;
}

// 把第i个元素向上移动
void ShiftUp(int a[], int i) {
    while(i>1 && a[i]>a[i/2]) {
        swap(a[i], a[i/2]);
        i >>= 1;
    }
}

// 把第i个元素向下移动
void ShiftDown(int a[], int n, int i) {
    while((i=2*i) <= n) {
        if(i+1<=n && a[i+1]>a[i]) ++i;
        if(a[i] > a[i/2]) swap(a[i], a[i/2]);
        else break;
    }
}

// 把数组a变成具备最大堆性质的数组
void MakeHeap(int a[], int n) {
    for(int i=n/2; i>0; --i)
        ShiftDown(a, n, i);
}

// 向堆中插入元素x
void Insert(int a[], int &n, int x) {
    a[++n] = x;
    ShiftUp(a, n);
}

// 删除堆中第i个元素
void Del(int a[], int &n, int i) {
    a[i] = a[n--];
    if(i>1 && a[i]>a[i/2]) ShiftUp(a, i);
    else ShiftDown(a, n, i);
}

// 堆排序,时间复杂度O(nlogn)
void HeapSort(int a[], int n) {
    MakeHeap(a, n);
    for(int i=n; i>1; --i) {
        swap(a[i], a[1]);
        ShiftDown(a, i-1, 1);
    }
}

字符串

程序1:循环输入并将每个单词插入集合S(忽略重复单词),然后排序输出。

int main(void) {
    set<string> s;
    set<string>::iterator j;
    string t;
    while(cin >> t)
        s.insert(t);
    for(j=s.begin(); j!=s.end(); ++j)
        cout<<*j<<endl;
    return 0;
}

程序2:单词计数

int main(void) {
    map<string, int> m;
    map<string, int>::iterator j;
    string t;
    while(cin >> t)
        m[t]++;
    for(j=m.begin(); j!=m.end(); ++j)
        cout<<j->first<<" "<<j->second<<endl;
    return 0;
}

程序3:建立自己的哈希表(散列表),以下是一种实现:

class Hash {
public:
    Hash(): seed_(131), size_(0) {
        memset(head_, 0, sizeof(head_));
    }
    
    void Insert(const char* str) {
        unsigned int id = hash(str);
        char *dst = (char*)node_[size_].word;
        while(*dst++ = *str++);
        node_[size_].next = head_[id];
        head_[id] = &node_[size_];
        ++size_;
    }

    bool Find(const char* str) {
        unsigned int id = hash(str);
        for(Node* p=head_[id]; p; p=p->next) {
            char* dst = (char*)p->word;
            int i = 0;
            for(; *(str+i) && *(str+i)==*(dst+i); ++i);
            if(!*(str+i) && !*(dst+i)) return true;
        }
        return false;
    }
    
private:
    unsigned int hash(const char* str) {// BKDR Hash Function
        unsigned int hash = 0;
        while(*str) {
            hash = hash * seed_ + (*str++);
        }
        return (hash & 0x7FFFFFFF) % kHashSize;
    }
    
private:
    unsigned int seed_;
    unsigned int size_;
    static const int kWordSize = 26 + 1;
    static const int kNodeSize = 20000;
    static const int kHashSize = 10001;
    struct Node {
        char word[kWordSize];
        Node *next;
    };
    Node node_[kNodeSize];
    Node* head_[kHashSize];
};

后缀数组

假设我们有以下字符串及一个char*数组:

 char c[20] = "hawstein";
 char* pc[20];

我们让指针pc[i]指向字符串的第i个字符,即:

for(int i=0; i<8; ++i)
    pc[i] = &c[i];

这时候我们输出pc[i],会得到字符串”hawstein”的所有后缀:

hawstein
awstein
wstein
stein
tein
ein
in
n

然后,我们对数组pc进行排序,将所有后缀按字典序排序:

sort(pc, pc+8, cmp);

其中,比较函数cmp如下:

inline bool cmp(char* p, char*q) {
    return strcmp(p, q) < 0;
}

这时,我们再输出pc[i],会得到排序后的结果:

awstein
ein
hawstein
in
n
stein
tein
wstein

我们把数组pc称为“后缀数组”。这里需要注意,数组pc 中存储的是指向每个后缀首字符的地址。我们也可以存储每个后缀首字符在原数组中的下标, 效果是一样的。

本章中用后缀数组解决了一个小问题:可重叠最长重复子串。比如对于字符串”banana”, 其后缀数组为:

a
ana
anana
banana
na
nana

扫描一次数组,比较相邻子串,找到相邻子串的最长公共前缀即可。本例为”ana”, 其中一个a是重叠的。

后缀数组是处理字符串的有力工具,常见的两种实现方法是:倍增算法和DC3算法。 推荐阅读以下材料来学习后缀数组:

许智磊,《后缀数组》

罗穗骞,《后缀数组——处理字符串的有力工具》

Google C++编程风格指南

Standard
July 14, 2013
作者:Hawstein
出处:http://hawstein.com/posts/google-cpp-style-guide.html
声明:本文采用以下协议进行授权: 自由转载-非商用-非衍生-保持署名|Creative Commons BY-NC-ND 3.0 ,转载请注明作者及出处。

前言

越来越发现一致的编程风格的重要性,于是把Google的C++编程风格指南看了一遍, 这里记录下于自己有益的rules。当规则有多个选择时,这里只记录个人习惯的用法, 并不代表它是唯一的用法。

Google Style Guide

Google开源项目风格指南

命名约定

命名管理是最重要的一致性规则,因此我把它放在最前面。

  • 尽可能给出描述性名称。
int num_errors; 
int num_completed_connections;
  • 文件名全部小写,用下划线做连接符。
my_useful_class.cc
  • C++文件以.cc 结尾,头文件以.h 结尾。(从.cpp切换到.cc)
my_useful_class.cc
my_useful_class.h
  • 类型命名每个单词以大写字母开头,不包含下划线。类、结构体、类型定义(typedef) 、枚举都使用相同约定。
// classes and structs
class UrlTable { ...
class UrlTableTester { ...
struct UrlTableProperties { ...

// typedefs
typedef hash_map<UrlTableProperties *, string> PropertiesMap;

// enums
enum UrlTableErrors { ...
  • 变量名一律小写,单词之间用下划线连接。类的成员变量以下划线结尾。
my_exciting_local_variable
my_exciting_member_variable_
  • 结构体的数据成员可以和普通变量一样,不用像类那样接下划线。
struct UrlTableProperties {
    string name;
    int num_entries;
}
  • 少用全局变量,要用的话用g作为其前缀(不喜欢用g_)。
bool gInvalid = false;
  • 常量命名在名称前加k。
const int kDaysInAWeek = 7;
  • 函数名的每个单词首字母大写,没有下划线。
AddTableEntry()
DeleteUrl()
  • 取值和设值函数要与存取的变量名匹配,使用小写单词及下划线。
class MyClass {
public:
    ...
    int num_entries() const { return num_entries_; }
    void set_num_entries(int num_entries) { num_entries_ = num_entries; }

private:
    int num_entries_;
};
  • 非常短小的内联函数也可以用小写字母命名。
void swap(int &a, int &b);
int max(int a, int b);
bool cmp(Type t1, Type t2);
  • 名字空间用小写字母命名,并基于项目名称和目录结构:
namespace google_awesome_project {
    ...
}
  • 枚举值应该优先采用常量的命名方式。
enum UrlTableErrors {
    kOK = 0,
    kErrorOutOfMemory,
    kErrorMalformedInput,
};
  • 尽量避免使用宏,如果不得不用,请使用大写字母及下划线。
#define ROUND(x) ...
#define PI_ROUNDED 3.0

把《The Swift Programming Language》读薄

Standard
July 1, 2014
作者:Hawstein
出处:http://hawstein.com/posts/make-thiner-tspl.html
声明:本文采用以下协议进行授权: 自由转载-非商用-非衍生-保持署名|Creative Commons BY-NC-ND 3.0 ,转载请注明作者及出处。

目录

  1. About Swift
  2. The Basics
  3. Basic Operators
  4. Strings and Characters
  5. Collection Types
  6. Control Flow
  7. Functions
  8. Closures
  9. Enumerations
  10. Classes and Structures
  11. Properties
  12. Methods
  13. Subscripts
  14. Inheritance
  15. Initialization
  16. Deinitialization
  17. Automatic Reference Counting
  18. Optional Chaining
  19. Type Casting
  20. Nested Types
  21. Extensions
  22. Protocols
  23. Generics
  24. Advanced Operators
  25. A Swift Tour // 放到最后避免有人看不懂

About Swift

We simplified memory management with Automatic Reference Counting.

Swift provides seamless access to existing Cocoa frameworks and mix-and-match interoperability with Objective-C code.

The Basics

let声明常量,var声明变量

You can access the minimum and maximum values of each integer type with its min and max properties.

虽然有UInt,但能用Int的时候就用Int。

// 各种进制的字面量表示
let decimalInteger = 17
let binaryInteger = 0b10001       // 17 in binary notation
let octalInteger = 0o21           // 17 in octal notation
let hexadecimalInteger = 0x11     // 17 in hexadecimal notation

// 更易于阅读的写法
let paddedDouble = 000123.456
let oneMillion = 1_000_000
let justOverOneMillion = 1_000_000.000_000_1

Floating-point values are always truncated when used to initialize a new integer value in this way. This means that 4.75 becomes 4, and -3.9 becomes -3.

// 定义类型别名 typealias
typealias AudioSample = UInt16 

// optional binding,只有当yyy是optional的时候才可以这样用。optional的yyy非空时为真,将yyy中的值取出赋给xxx,空时(nil)为假;

if let xxx = yyy {
     // do something
} else {
     // do other thing
}

// decompose一个tuple时,对于不想使用的元素用’_’接收
let http404Error = (404, "Not Found")
let (justTheStatusCode, _) = http404Error
println("The status code is \(justTheStatusCode)")
// prints "The status code is 404

let possibleNumber = "123"
let convertedNumber = possibleNumber.toInt()
// convertedNumber is inferred to be of type "Int?", or "optional Int”,因为toInt()可能会失败(比如“123a”)导致返回nil

You can use an if statement to find out whether an optional contains a value. If an optional does have a value, it evaluates to true; if it has no value at all, it evaluates to false.

Once you’re sure that the optional does contain a value, you can access its underlying value by adding an exclamation mark (!) to the end of the optional’s name. The exclamation mark effectively says, “I know that this optional definitely has a value; please use it.” This is known as forced unwrapping of the optional’s value。

If you define an optional constant or variable without providing a default value, the constant or variable is automatically set to nil for you.

Basic Operators

Unlike C, Swift lets you perform remainder (%) calculations on floating-point numbers.

if x = y {
    // this is not valid, because x = y does not return a value
}

// Swift中的取模操作
-9 % 4   // equals -1,理解成:-9 = (4 × -2) + -1

Swift also provides two identity operators (=== and !==), which you use to test whether two object references both refer to the same object instance

// ???
var arr1 = [1, 2, 3]
var arr2 = arr1
arr2[0] = 10;
arr1     // [10, 2, 3]
arr2     // [10, 2, 3]
arr1 === arr2  // 修改arr2,arr1也跟着修改,所以应该是指向一个object,这里应该是true,但结果却是false

String and Characters

Swift’s String type is a value type. If you create a new String value, that String value is copied when it is passed to a function or method, or when it is assigned to a constant or variable.

String判断是否包含某前缀或后缀的方法:hasPrefix,hasSuffix

String怎么随机取其中一个字符?

Collection Types

// arr随着brr改变
var arr = ["hello", "world"]
var brr = arr
brr[0] = "haw"
brr     // ["haw", "world"]
arr     // ["haw", "world"]


// arr不随brr改变,说明brr原本与arr指向一块内存,以下操作后指向新的内存,并把数组中的元素值copy了一遍。
// 长度发生变化时,Array会发生拷贝
var arr = ["hello", "world"]
var brr = arr
brr[0..0] = ["haw"]
brr     // ["haw", "hello", "world”]
arr      //  ["hello", "world"]


// arr不随brr改变,同上
var arr = ["hello", "world"]
var brr = arr
brr.insert("haw", atIndex: 0)      // remove也一样

brr     // ["haw", "hello", "world”]
arr      //  ["hello", "world"]
for (index, value) in enumerate(shoppingList) {
    println("Item \(index + 1): \(value)")
}
// Item 1: Six eggs
// Item 2: Milk
// Item 3: Flour
// Item 4: Baking Powder
// Item 5: Bananas
var threeDoubles = Double[](count: 3, repeatedValue: 0.0)
// threeDoubles is of type Double[], and equals [0.0, 0.0, 0.0]
var anotherThreeDoubles = Array(count: 3, repeatedValue: 2.5)
// anotherThreeDoubles is inferred as Double[], and equals [2.5, 2.5, 2.5]

The only restriction is that KeyType must be hashable—that is, it must provide a way to make itself uniquely representable. All of Swift’s basic types (such as String, Int, Double, and Bool) are hashable by default, and all of these types can be used as the keys of a dictionary. Enumeration member values without associated values (as described in Enumerations) are also hashable by default.

// 以下将字典airports中key为DUB的值更新为Dublin International,返回的是它原来的值
if let oldValue = airports.updateValue("Dublin International", forKey: "DUB") {
    println("The old value for DUB was \(oldValue).")
}
// prints "The old value for DUB was Dublin.

You can also use subscript syntax to retrieve a value from the dictionary for a particular key. Because it is possible to request a key for which no value exists, a dictionary’s subscript returns an optional value of the dictionary’s value type.

airports["APL"] = "Apple International"
// "Apple International" is not the real airport for APL, so delete it
airports["APL"] = nil
// APL has now been removed from the dictionary

if let removedValue = airports.removeValueForKey("DUB") {
    println("The removed airport's name is \(removedValue).")
} else {
    println("The airports dictionary does not contain a value for DUB.")
}
// prints "The removed airport's name is Dublin International.

//
for airportCode in airports.keys {
    println("Airport code: \(airportCode)")
}
// Airport code: TYO
// Airport code: LHR

for airportName in airports.values {
    println("Airport name: \(airportName)")
}
// Airport name: Tokyo
// Airport name: London Heathrow

let airportCodes = Array(airports.keys)
// airportCodes is ["TYO", "LHR"]

let airportNames = Array(airports.values)
// airportNames is ["Tokyo", "London Heathrow"]

Arrays and dictionaries store multiple values together in a single collection. If you create an array or a dictionary and assign it to a variable, the collection that is created will be mutable. This means that you can change (or mutate) the size of the collection after it is created by adding more items to the collection, or by removing existing items from the ones it already contains. Conversely, if you assign an array or a dictionary to a constant, that array or dictionary is immutable, and its size cannot be changed.

For dictionaries, immutability also means that you cannot replace the value for an existing key in the dictionary. An immutable dictionary’s contents cannot be changed once they are set.

Immutability has a slightly different meaning for arrays, however. You are still not allowed to perform any action that has the potential to change the size of an immutable array, but you are allowed to set a new value for an existing index in the array. This enables Swift’s Array type to provide optimal performance for array operations when the size of an array is fixed.

Control Flow

let base = 3
let power = 10
var answer = 1
for _ in 1...power {
    answer *= base
}
println("\(base) to the power of \(power) is \(answer)")
// prints "3 to the power of 10 is 59049

switch中的case情况要穷尽所有的可能性,如果可以穷尽(比如case是enum类型的有限几个值)则可以不加default,否则一定要加default。case中可以使用区间,开闭都可以。

let count = 3_000_000_000_000
let countedThings = "stars in the Milky Way"
var naturalCount: String
switch count {
case 0:
    naturalCount = "no"
case 1...3:
    naturalCount = "a few"
case 4...9:
    naturalCount = "several"
case 10...99:
    naturalCount = "tens of"
case 100...999:
    naturalCount = "hundreds of"
case 1000...999_999:
    naturalCount = "thousands of"
default:
    naturalCount = "millions and millions of"
}
println("There are \(naturalCount) \(countedThings).")
// prints "There are millions and millions of stars in the Milky Way.


let somePoint = (1, 1)
switch somePoint {
case (0, 0):
    println("(0, 0) is at the origin")
case (_, 0):
    println("(\(somePoint.0), 0) is on the x-axis")
case (0, _):
    println("(0, \(somePoint.1)) is on the y-axis")
case (-2...2, -2...2):
    println("(\(somePoint.0), \(somePoint.1)) is inside the box")
default:
    println("(\(somePoint.0), \(somePoint.1)) is outside of the box")
}
// prints "(1, 1) is inside the box

Unlike C, Swift allows multiple switch cases to consider the same value or values. In fact, the point (0, 0) could match all four of the cases in this example. However, if multiple matches are possible, the first matching case is always used. The point (0, 0) would match case (0, 0) first, and so all other matching cases would be ignored.

switch anotherPoint {
case (let x, 0):
    println("on the x-axis with an x value of \(x)")
case (0, let y):
    println("on the y-axis with a y value of \(y)")
case let (x, y):
    println("somewhere else at (\(x), \(y))")
}
// prints "on the x-axis with an x value


let yetAnotherPoint = (1, -1)
switch yetAnotherPoint {
case let (x, y) where x == y:
    println("(\(x), \(y)) is on the line x == y")
case let (x, y) where x == -y:
    println("(\(x), \(y)) is on the line x == -y")
case let (x, y):
    println("(\(x), \(y)) is just some arbitrary point")
}
// prints "(1, -1) is on the line x == -y 

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."
}
println(description)
// prints "The number 5 is a prime number, and also an integer.


gameLoop: while square != finalSquare {
    if ++diceRoll == 7 { diceRoll = 1 }
    switch square + diceRoll {
    case finalSquare:
        // diceRoll will move us to the final square, so the game is over
        break gameLoop
    case let newSquare where newSquare > finalSquare:
        // diceRoll will move us beyond the final square, so roll again
        continue gameLoop
    default:
        // this is a valid move, so find out its effect
        square += diceRoll
        square += board[square]
    }
}
println("Game over!")

Functions

If you provide an external parameter name for a parameter, that external name must always be used when calling the function.

func join(string s1: String, toString s2: String, withJoiner joiner: String)
    -> String {
        return s1 + joiner + s2
}
join(string: "hello", toString: "world", withJoiner: ", ")
// returns "hello, world"  
func containsCharacter(#string: String, #characterToFind: Character) -> Bool {
    for character in string {
        if character == characterToFind {
            return true
        }
    }
    return false
}

let containsAVee = containsCharacter(string: "aardvark", characterToFind: "v")
// containsAVee equals true, because "aardvark" contains a "v"
func join(string s1: String, toString s2: String,
    withJoiner joiner: String = " ") -> String {
        return s1 + joiner + s2
}
join(string: "hello", toString: "world", withJoiner: "-")
// returns "hello-world”
join(string: "hello", toString: "world")
// returns "hello world"   
func join(s1: String, s2: String, joiner: String = " ") -> String {
    return s1 + joiner + s2
}
join("hello", "world", joiner: "-")
// returns "hello-world”  有默认值的参数,如果你没有使用外部参数名,Swift会自动提供一个和内部参数名一样的外部参数名
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)
// returns 3.0, which is the arithmetic mean of these five numbers
arithmeticMean(3, 8, 19)
// returns 10.0, which is the arithmetic mean of these three numbers 

A function may have at most one variadic parameter, and it must always appear last in the parameter list, to avoid ambiguity when calling the function with multiple parameters.

If your function has one or more parameters with a default value, and also has a variadic parameter, place the variadic parameter after all the defaulted parameters at the very end of the list.

形参默认是常量,如果要改变形参,需要用var显式声明为变量 // swift中有许多默认情况和主流(比如C\C++)语言都是相反的,它将更常见的情况设定为默认

func alignRight(var string: String, count: Int, pad: Character) -> String {
    let amountToPad = count - countElements(string)
    for _ in 1...amountToPad {
        string = pad + string
    }
    return string
}
let originalString = "hello"
let paddedString = alignRight(originalString, 10, "-")
// paddedString is equal to "-----hello"
// originalString is still equal to "hello" 

In-out parameters cannot have default values, and variadic parameters cannot be marked as inout. If you mark a parameter as inout, it cannot also be marked as var or let.

func swapTwoInts(inout a: Int, inout b: Int) { // 类似于引用传参
    let temporaryA = a
    a = b
    b = temporaryA
} 

var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt)
println("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
// prints "someInt is now 107, and anotherInt is now 3" 

像定义常量或变量一样定义函数:

var mathFunction: (Int, Int) -> Int = addTwoInts
println("Result: \(mathFunction(2, 3))")
// prints "Result: 5”

let anotherMathFunction = addTwoInts
// anotherMathFunction is inferred to be of type (Int, Int) -> Int   
func printMathResult(mathFunction: (Int, Int) -> Int, a: Int, b: Int) {
    println("Result: \(mathFunction(a, b))")
}
printMathResult(addTwoInts, 3, 5)
// prints "Result: 8" 

Swift支持嵌套函数:

func chooseStepFunction(backwards: Bool) -> (Int) -> Int {
    func stepForward(input: Int) -> Int { return input + 1 }
    func stepBackward(input: Int) -> Int { return input - 1 }
    return backwards ? stepBackward : stepForward
}
var currentValue = -4
let moveNearerToZero = chooseStepFunction(currentValue > 0)
// moveNearerToZero now refers to the nested stepForward() function
while currentValue != 0 {
    println("\(currentValue)... ")
    currentValue = moveNearerToZero(currentValue)
}
println("zero!")
// -4...
// -3...
// -2...
// -1...
// zero! 

Closures

Global and nested functions, as introduced in Functions, are actually special cases of closures. Closures take one of three forms:

  • Global functions are closures that have a name and do not capture any values.
  • Nested functions are closures that have a name and can capture values from their enclosing function.
  • Closure expressions are unnamed closures written in a lightweight syntax that can capture values from their surrounding context.

Closure expression syntax has the following general form:

{ (parameters) -> return type in
    statements
}
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella”]
func backwards(s1: String, s2: String) -> Bool {
    return s1 > s2
}
// 方法1
var reversed = sort(names, backwards)
// reversed is equal to ["Ewa", "Daniella", "Chris", "Barry", "Alex”]  

// 1.5
reversed = sort(names, { (s1: String, s2: String) -> Bool in return s1 > s2 } )

// 方法2
reversed = sort(names, { s1, s2 in return s1 > s2 } ) 

// 方法3
reversed = sort(names, { s1, s2 in s1 > s2 } ) // Implicit Returns from Single-Expression Closures

// 方法4
reversed = sort(names, { $0 > $1 } )  

// 方法5
reversed = sort(names, >) 

// 方法6
reversed = sort(names) { $0 > $1 } 

It is always possible to infer parameter types and return type when passing a closure to a function as an inline closure expression. As a result, you rarely need to write an inline closure in its fullest form.

func someFunctionThatTakesAClosure(closure: () -> ()) {
    // function body goes here
}

// here's how you call this function without using a trailing closure:

someFunctionThatTakesAClosure({
    // closure's body goes here
    })

// here's how you call this function with a trailing closure instead:

someFunctionThatTakesAClosure() {
    // trailing closure's body goes here
} 

If a closure expression is provided as the function’s only argument and you provide that expression as a trailing closure, you do not need to write a pair of parentheses () after the function’s name when you call the function.

let digitNames = [
    0: "Zero", 1: "One", 2: "Two",   3: "Three", 4: "Four",
    5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"
]
let numbers = [16, 58, 510] 
let strings = numbers.map {
    (var number) -> String in
    var output = ""
    while number > 0 {
        output = digitNames[number % 10]! + output
        number /= 10
    }
    return output
}
// strings is inferred to be of type String[]
// its value is ["OneSix", "FiveEight", "FiveOneZero"] 
func makeIncrementor(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    func incrementor() -> Int {
        runningTotal += amount
        return runningTotal
    }
    return incrementor
}

let incrementByTen = makeIncrementor(forIncrement: 10)
incrementByTen()
// returns a value of 10
incrementByTen()
// returns a value of 20
incrementByTen()
// returns a value of 30

let incrementBySeven = makeIncrementor(forIncrement: 7)
incrementBySeven()
// returns a value of 7
incrementByTen()
// returns a value of 40    

let alsoIncrementByTen = incrementByTen
alsoIncrementByTen()
// returns a value of 50 

functions and closures are reference types.

Enumerations

enum CompassPoint {
    case North
    case South
    case East
    case West
} 

enum Planet {
    case Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune
}

var directionToHead = CompassPoint.West
directionToHead = .East   

directionToHead = .South
switch directionToHead {
case .North:
    println("Lots of planets have a north")
case .South:
    println("Watch out for penguins")
case .East:
    println("Where the sun rises")
case .West:
    println("Where the skies are blue")
}
// prints "Watch out for penguins" 
let somePlanet = Planet.Earth
switch somePlanet {
case .Earth:
    println("Mostly harmless")
default:
    println("Not a safe place for humans")
}
// prints "Mostly harmless" 
enum Barcode {
    case UPCA(Int, Int, Int)
    case QRCode(String)
}

var productBarcode = Barcode.UPCA(8, 85909_51226, 3)
productBarcode = .QRCode("ABCDEFGHIJKLMNOP”)

switch productBarcode {
case .UPCA(let numberSystem, let identifier, let check):
    println("UPC-A with value of \(numberSystem), \(identifier), \(check).")
case .QRCode(let productCode):
    println("QR code with value of \(productCode).")
}
// prints "QR code with value of ABCDEFGHIJKLMNOP.”    

switch productBarcode {
case let .UPCA(numberSystem, identifier, check):
    println("UPC-A with value of \(numberSystem), \(identifier), \(check).")
case let .QRCode(productCode):
    println("QR code with value of \(productCode).")
}
// prints "QR code with value of ABCDEFGHIJKLMNOP." 
// raw values
enum ASCIIControlCharacter: Character {
    case Tab = "\t"
    case LineFeed = "\n"
    case CarriageReturn = "\r"
} 

enum Planet: Int {
    case Mercury = 1, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune
} 

let earthsOrder = Planet.Earth.toRaw()
// earthsOrder is 3

let possiblePlanet = Planet.fromRaw(7)
// possiblePlanet is of type Planet? and equals Planet.Uranus

let positionToFind = 9
if let somePlanet = Planet.fromRaw(positionToFind) {
    switch somePlanet {
    case .Earth:
        println("Mostly harmless")
    default:
        println("Not a safe place for humans")
    }
} else {
    println("There isn't a planet at position \(positionToFind)")
}
// prints "There isn't a planet at position 9"   

Classes and Structures

Classes have additional capabilities that structures do not:

Inheritance enables one class to inherit the characteristics of another. Type casting enables you to check and interpret the type of a class instance at runtime. Deinitializers enable an instance of a class to free up any resources it has assigned. Reference counting allows more than one reference to a class instance.

Structures are always copied when they are passed around in your code, and do not use reference counting.

if tenEighty === alsoTenEighty {
    println("tenEighty and alsoTenEighty refer to the same Resolution instance.")
}
// prints "tenEighty and alsoTenEighty refer to the same Resolution instance.”

Whenever you assign a Dictionary instance to a constant or variable, or pass a Dictionary instance as an argument to a function or method call, the dictionary is copied at the point that the assignment or call takes place.

var ages = ["Peter": 23, "Wei": 35, "Anish": 65, "Katya": 19]
var copiedAges = ages  
copiedAges["Peter"] = 24
println(ages["Peter"])
// prints "23" 

If you assign an Array instance to a constant or variable, or pass an Array instance as an argument to a function or method call, the contents of the array are not copied at the point that the assignment or call takes place. Instead, both arrays share the same sequence of element values. When you modify an element value through one array, the result is observable through the other.

For arrays, copying only takes place when you perform an action that has the potential to modify the length of the array. This includes appending, inserting, or removing items, or using a ranged subscript to replace a range of items in the array.

var a = [1, 2, 3]
var b = a
var c = a

println(a[0])
// 1
println(b[0])
// 1
println(c[0])
// 1

a[0] = 42
println(a[0])
// 42
println(b[0])
// 42
println(c[0])
// 42

a.append(4)
a[0] = 777
println(a[0])
// 777
println(b[0])
// 42
println(c[0])
// 42

b.unshare()

b[0] = -105
println(a[0])
// 777
println(b[0])
// -105
println(c[0])
// 42

if b === c {
    println("b and c still share the same array elements.")
} else {
    println("b and c now refer to two independent sets of array elements.")
}
// prints "b and c now refer to two independent sets of array elements."       
var names = ["Mohsen", "Hilary", "Justyn", "Amy", "Rich", "Graham", "Vic"]
var copiedNames = names.copy()
copiedNames[0] = "Mo"
println(names[0])
// prints "Mohsen"  

If you simply need to be sure that your reference to an array’s contents is the only reference in existence, call the unshare method, not the copy method. The unshare method does not make a copy of the array unless it is necessary to do so. The copy method always copies the array, even if it is already unshared.

Properties

Computed properties are provided by classes, structures, and enumerations. Stored properties are provided only by classes and structures.

let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4)
// this range represents integer values 0, 1, 2, and 3
rangeOfFourItems.firstValue = 6
// this will report an error, even thought firstValue is a variable property 

Because rangeOfFourItems is declared as a constant (with the let keyword), it is not possible to change its firstValue property, even though firstValue is a variable property.

This behavior is due to structures being value types. When an instance of a value type is marked as a constant, so are all of its properties.

The same is not true for classes, which are reference types. If you assign an instance of a reference type to a constant, you can still change that instance’s variable properties.

class DataImporter {
    /*
    DataImporter is a class to import data from an external file.
    The class is assumed to take a non-trivial amount of time to initialize.
    */
    var fileName = "data.txt"
    // the DataImporter class would provide data importing functionality here
}

class DataManager {
    @lazy var importer = DataImporter()
    var data = String[]()
    // the DataManager class would provide data management functionality here
}

let manager = DataManager()
manager.data += "Some data"
manager.data += "Some more data"
// the DataImporter instance for the importer property has not yet been created

println(manager.importer.fileName)
// the DataImporter instance for the importer property has now been created
// prints "data.txt"  

In addition to stored properties, classes, structures, and enumerations can define computed properties, which do not actually store a value. Instead, they provide a getter and an optional setter to retrieve and set other properties and values indirectly.

struct Point {
    var x = 0.0, y = 0.0
}
struct Size {
    var width = 0.0, height = 0.0
}
struct Rect {
    var origin = Point()
    var size = Size()
    var center: Point { // center是computed property
    get {
        let centerX = origin.x + (size.width / 2)
        let centerY = origin.y + (size.height / 2)
        return Point(x: centerX, y: centerY)
    }
    set(newCenter) {
        origin.x = newCenter.x - (size.width / 2)
        origin.y = newCenter.y - (size.height / 2)
    }
    }
}
var square = Rect(origin: Point(x: 0.0, y: 0.0),
    size: Size(width: 10.0, height: 10.0))
let initialSquareCenter = square.center
square.center = Point(x: 15.0, y: 15.0)
println("square.origin is now at (\(square.origin.x), \(square.origin.y))")
// prints "square.origin is now at (10.0, 10.0)" 

You must declare computed properties—including read-only computed properties—as variable properties with the var keyword, because their value is not fixed.

struct Cuboid {
    var width = 0.0, height = 0.0, depth = 0.0
    var volume: Double {
    return width * height * depth
    }
}
let fourByFiveByTwo = Cuboid(width: 4.0, height: 5.0, depth: 2.0)
println("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)")
// prints "the volume of fourByFiveByTwo is 40.0” 

willSet and didSet observers are not called when a property is first initialized. They are only called when the property’s value is set outside of an initialization context.

class StepCounter {
    var totalSteps: Int = 0 {
    willSet(newTotalSteps) {
        println("About to set totalSteps to \(newTotalSteps)")
    }
    didSet {
        if totalSteps > oldValue  {
            println("Added \(totalSteps - oldValue) steps")
        }
    }
    }
}
let stepCounter = StepCounter()
stepCounter.totalSteps = 200
// About to set totalSteps to 200
// Added 200 steps
stepCounter.totalSteps = 360
// About to set totalSteps to 360
// Added 160 steps
stepCounter.totalSteps = 896
// About to set totalSteps to 896
// Added 536 steps 

If you assign a value to a property within its own didSet observer, the new value that you assign will replace the one that was just set.

Global constants and variables are always computed lazily, in a similar manner to Lazy Stored Properties. Unlike lazy stored properties, global constants and variables do not need to be marked with the @lazy attribute. Local constants and variables are never computed lazily.

For value types (that is, structures and enumerations), you can define stored and computed type properties. For classes, you can define computed type properties only.

Unlike stored instance properties, you must always give stored type properties a default value. This is because the type itself does not have an initializer that can assign a value to a stored type property at initialization time.

struct SomeStructure {
    static var storedTypeProperty = "Some value."
    static var computedTypeProperty: Int {
    // return an Int value here
    }
}
enum SomeEnumeration {
    static var storedTypeProperty = "Some value."
    static var computedTypeProperty: Int {
    // return an Int value here
    }
}
class SomeClass {
    class var computedTypeProperty: Int {
    // return an Int value here
    }
} 

println(SomeClass.computedTypeProperty)
// prints "42"

println(SomeStructure.storedTypeProperty)
// prints "Some value."
SomeStructure.storedTypeProperty = "Another value."
println(SomeStructure.storedTypeProperty)
// prints "Another value." 
struct AudioChannel {
    static let thresholdLevel = 10
    static var maxInputLevelForAllChannels = 0
    var currentLevel: Int = 0 {
    didSet {
        if currentLevel > AudioChannel.thresholdLevel {
            // cap the new audio level to the threshold level
            currentLevel = AudioChannel.thresholdLevel
        }
        if currentLevel > AudioChannel.maxInputLevelForAllChannels {
            // store this as the new overall maximum input level
            AudioChannel.maxInputLevelForAllChannels = currentLevel
        }
    }
    }
}

var leftChannel = AudioChannel()
var rightChannel = AudioChannel()

leftChannel.currentLevel = 7
println(leftChannel.currentLevel)
// prints "7"
println(AudioChannel.maxInputLevelForAllChannels)
// prints “7"

rightChannel.currentLevel = 11
println(rightChannel.currentLevel)
// prints "10"
println(AudioChannel.maxInputLevelForAllChannels)
// prints "10"    

Methods

Structures and enumerations are value types. By default, the properties of a value type cannot be modified from within its instance methods.

struct Point {
    var x = 0.0, y = 0.0
    mutating func moveByX(deltaX: Double, y deltaY: Double) {
        x += deltaX
        y += deltaY
    }
}
var somePoint = Point(x: 1.0, y: 1.0)
somePoint.moveByX(2.0, y: 3.0)
println("The point is now at (\(somePoint.x), \(somePoint.y))")
// prints "The point is now at (3.0, 4.0)" 
let fixedPoint = Point(x: 3.0, y: 3.0)
fixedPoint.moveByX(2.0, y: 3.0)
// this will report an error 
enum TriStateSwitch {
    case Off, Low, High
    mutating func next() {
        switch self {
        case Off:
            self = Low
        case Low:
            self = High
        case High:
            self = Off
        }
    }
}
var ovenLight = TriStateSwitch.Low
ovenLight.next()
// ovenLight is now equal to .High
ovenLight.next()
// ovenLight is now equal to .Off 
struct LevelTracker {
    static var highestUnlockedLevel = 1
    static func unlockLevel(level: Int) {
        if level > highestUnlockedLevel { highestUnlockedLevel = level }
    }
    static func levelIsUnlocked(level: Int) -> Bool {
        return level <= highestUnlockedLevel
    }
    var currentLevel = 1
    mutating func advanceToLevel(level: Int) -> Bool {
        if LevelTracker.levelIsUnlocked(level) {
            currentLevel = level
            return true
        } else {
            return false
        }
    }
}

class Player {
    var tracker = LevelTracker()
    let playerName: String
    func completedLevel(level: Int) {
        LevelTracker.unlockLevel(level + 1)
        tracker.advanceToLevel(level + 1)
    }
    init(name: String) {
        playerName = name
    }
}

var player = Player(name: "Argyrios")
player.completedLevel(1)
println("highest unlocked level is now \(LevelTracker.highestUnlockedLevel)")
// prints "highest unlocked level is now 2”

player = Player(name: "Beto")
if player.tracker.advanceToLevel(6) {
    println("player is now on level 6")
} else {
    println("level 6 has not yet been unlocked")
}
// prints "level 6 has not yet been unlocked"    

Subscripts

subscript(index: Int) -> Int {
    get {
        // return an appropriate subscript value here
    }
    set(newValue) {
        // perform a suitable setting action here
    }
}

// read-only subscript
subscript(index: Int) -> Int {
    // return an appropriate subscript value here
}

struct TimesTable {
    let multiplier: Int
    subscript(index: Int) -> Int {
        return multiplier * index
    }
}
let threeTimesTable = TimesTable(multiplier: 3)
println("six times three is \(threeTimesTable[6])")
// prints "six times three is 18" 
struct Matrix {
    let rows: Int, columns: Int
    var grid: Double[]
    init(rows: Int, columns: Int) {
        self.rows = rows
        self.columns = columns
        grid = Array(count: rows * columns, repeatedValue: 0.0)
    }
    func indexIsValidForRow(row: Int, column: Int) -> Bool {
        return row >= 0 && row < rows && column >= 0 && column < columns
    }
    subscript(row: Int, column: Int) -> Double {
        get {
            assert(indexIsValidForRow(row, column: column), "Index out of range")
            return grid[(row * columns) + column]
        }
        set {
            assert(indexIsValidForRow(row, column: column), "Index out of range")
            grid[(row * columns) + column] = newValue
        }
    }
}

var matrix = Matrix(rows: 2, columns: 2)
matrix[0, 1] = 1.5
matrix[1, 0] = 3.2

let someValue = matrix[2, 2]
// this triggers an assert, because [2, 2] is outside of the matrix bounds    

Inheritance

Swift classes do not inherit from a universal base class. Classes you define without specifying a superclass automatically become base classes for you to build upon.

class Car: Vehicle {
    var speed: Double = 0.0
    init() {
        super.init()
        maxPassengers = 5
        numberOfWheels = 4
    }
    override func description() -> String {
        return super.description() + "; "
            + "traveling at \(speed) mph"
    }
} 

You can present an inherited read-only property as a read-write property by providing both a getter and a setter in your subclass property override. You cannot, however, present an inherited read-write property as a read-only property.

You can prevent a method, property, or subscript from being overridden by marking it as final

Initialization

Classes and structures must set all of their stored properties to an appropriate initial value by the time an instance of that class or structure is created. Stored properties cannot be left in an indeterminate state.

Swift provides an automatic external name for every parameter in an initializer if you don’t provide an external name yourself. This automatic external name is the same as the local name, as if you had written a hash symbol before every initialization parameter.

If you do not want to provide an external name for a parameter in an initializer, provide an underscore (_) as an explicit external name for that parameter to override the default behavior described above.

struct Color {
    let red = 0.0, green = 0.0, blue = 0.0
    init(red: Double, green: Double, blue: Double) {
        self.red   = red
        self.green = green
        self.blue  = blue
    }
}

let magenta = Color(red: 1.0, green: 0.0, blue: 1.0)  

let veryGreen = Color(0.0, 1.0, 0.0)
// this reports a compile-time error - external names are required 

You can modify the value of a constant property at any point during initialization, as long as it is set to a definite value by the time initialization finishes.

class SurveyQuestion {
    let text: String
    var response: String?
    init(text: String) {
        self.text = text
    }
    func ask() {
        println(text)
    }
}
let beetsQuestion = SurveyQuestion(text: "How about beets?")
beetsQuestion.ask()
// prints "How about beets?"
beetsQuestion.response = "I also like beets. (But not with cheese.)" 

structure types automatically receive a memberwise initializer if they provide default values for all of their stored properties and do not define any of their own custom initializers.

struct Size {
    var width = 0.0, height = 0.0
}
let twoByTwo = Size(width: 2.0, height: 2.0) 

If you want your custom value type to be initializable with the default initializer and memberwise initializer, and also with your own custom initializers, write your custom initializers in an extension rather than as part of the value type’s original implementation.

Designated initializers are the primary initializers for a class. A designated initializer fully initializes all properties introduced by that class and calls an appropriate superclass initializer to continue the initialization process up the superclass chain.

Convenience initializers are secondary, supporting initializers for a class. You can define a convenience initializer to call a designated initializer from the same class as the convenience initializer with some of the designated initializer’s parameters set to default values. You can also define a convenience initializer to create an instance of that class for a specific use case or input value type.

To simplify the relationships between designated and convenience initializers, Swift applies the following three rules for delegation calls between initializers:

Rule 1: Designated initializers must call a designated initializer from their immediate superclass.

Rule 2: Convenience initializers must call another initializer available in the same class.

Rule 3: Convenience initializers must ultimately end up calling a designated initializer.

A simple way to remember this is:

Designated initializers must always delegate up. Convenience initializers must always delegate across.

Class initialization in Swift is a two-phase process. In the first phase, each stored property is assigned an initial value by the class that introduced it. Once the initial state for every stored property has been determined, the second phase begins, and each class is given the opportunity to customize its stored properties further before the new instance is considered ready for use.

class Food {
    var name: String
    init(name: String) {
        self.name = name
    }
    convenience init() {
        self.init(name: "[Unnamed]")
    }
} 

let namedMeat = Food(name: "Bacon")
// namedMeat's name is “Bacon"

let mysteryMeat = Food()
// mysteryMeat's name is "[Unnamed]”  

class RecipeIngredient: Food {
    var quantity: Int
    init(name: String, quantity: Int) {
        self.quantity = quantity
        super.init(name: name)
    }
    convenience init(name: String) {
        self.init(name: name, quantity: 1)
    }
}

let oneMysteryItem = RecipeIngredient()
let oneBacon = RecipeIngredient(name: "Bacon")
let sixEggs = RecipeIngredient(name: "Eggs", quantity: 6)

class ShoppingListItem: RecipeIngredient {
    var purchased = false
    var description: String {
    var output = "\(quantity) x \(name.lowercaseString)"
        output += purchased ? " ✔" : " ✘"
        return output
    }
}

var breakfastList = [
    ShoppingListItem(),
    ShoppingListItem(name: "Bacon"),
    ShoppingListItem(name: "Eggs", quantity: 6),
]
breakfastList[0].name = "Orange juice"
breakfastList[0].purchased = true
for item in breakfastList {
    println(item.description)
}
// 1 x orange juice ✔
// 1 x bacon ✘
// 6 x eggs ✘    
class SomeClass {
    let someProperty: SomeType = {
        // create a default value for someProperty inside this closure
        // someValue must be of the same type as SomeType
        return someValue
        }()
}

Note that the closure’s end curly brace is followed by an empty pair of parentheses. This tells Swift to execute the closure immediately.

struct Checkerboard {
    let boardColors: Bool[] = {
        var temporaryBoard = Bool[]()
        var isBlack = false
        for i in 1...10 {
            for j in 1...10 {
                temporaryBoard.append(isBlack)
                isBlack = !isBlack
            }
            isBlack = !isBlack
        }
        return temporaryBoard
        }()
    func squareIsBlackAtRow(row: Int, column: Int) -> Bool {
        return boardColors[(row * 10) + column]
    }
}

let board = Checkerboard()
println(board.squareIsBlackAtRow(0, column: 1))
// prints "true"
println(board.squareIsBlackAtRow(9, column: 9))
// prints "false"  

Deinitialization

Deinitializers are only available on class types.

deinit {
    // perform the deinitialization
} 
struct Bank {
    static var coinsInBank = 10_000
    static func vendCoins(var numberOfCoinsToVend: Int) -> Int {
        numberOfCoinsToVend = min(numberOfCoinsToVend, coinsInBank)
        coinsInBank -= numberOfCoinsToVend
        return numberOfCoinsToVend
    }
    static func receiveCoins(coins: Int) {
        coinsInBank += coins
    }
}

lass Player {
    var coinsInPurse: Int
    init(coins: Int) {
        coinsInPurse = Bank.vendCoins(coins)
    }
    func winCoins(coins: Int) {
        coinsInPurse += Bank.vendCoins(coins)
    }
    deinit {
        Bank.receiveCoins(coinsInPurse)
    }
}

var playerOne: Player? = Player(coins: 100)
println("A new player has joined the game with \(playerOne!.coinsInPurse) coins")
// prints "A new player has joined the game with 100 coins"
println("There are now \(Bank.coinsInBank) coins left in the bank")
// prints "There are now 9900 coins left in the bank”

playerOne!.winCoins(2_000)
println("PlayerOne won 2000 coins & now has \(playerOne!.coinsInPurse) coins")
// prints "PlayerOne won 2000 coins & now has 2100 coins"
println("The bank now only has \(Bank.coinsInBank) coins left")
// prints "The bank now only has 7900 coins left”

playerOne = nil
println("PlayerOne has left the game")
// prints "PlayerOne has left the game"
println("The bank now has \(Bank.coinsInBank) coins")
// prints "The bank now has 10000 coins"     

Automatic Reference Counting

class Person {
    let name: String
    init(name: String) { self.name = name }
    var apartment: Apartment?
    deinit { println("\(name) is being deinitialized") }
}

class Apartment {
    let number: Int
    init(number: Int) { self.number = number }
    var tenant: Person?
    deinit { println("Apartment #\(number) is being deinitialized") }
}

var john: Person?
var number73: Apartment?

john = Person(name: "John Appleseed")
number73 = Apartment(number: 73)

john!.apartment = number73
number73!.tenant = john    

Resolving Strong Reference Cycles Between Class Instances: Weak References

class Person {
    let name: String
    init(name: String) { self.name = name }
    var apartment: Apartment?
    deinit { println("\(name) is being deinitialized") }
}

class Apartment {
    let number: Int
    init(number: Int) { self.number = number }
    weak var tenant: Person?
    deinit { println("Apartment #\(number) is being deinitialized") }
}

var john: Person?
var number73: Apartment?

john = Person(name: "John Appleseed")
number73 = Apartment(number: 73)

john!.apartment = number73
number73!.tenant = john  

Resolving Strong Reference Cycles Between Class Instances: Unowned References

class Customer {
    let name: String
    var card: CreditCard?
    init(name: String) {
        self.name = name
    }
    deinit { println("\(name) is being deinitialized") }
}

class CreditCard {
    let number: Int
    unowned let customer: Customer
    init(number: Int, customer: Customer) {
        self.number = number
        self.customer = customer
    }
    deinit { println("Card #\(number) is being deinitialized") }
}

var john: Customer?
john = Customer(name: "John Appleseed")
john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)   

Unowned References and Implicitly Unwrapped Optional Properties

class Country {
    let name: String
    let capitalCity: City!
    init(name: String, capitalName: String) {
        self.name = name
        self.capitalCity = City(name: capitalName, country: self)
    }
}

class City {
    let name: String
    unowned let country: Country
    init(name: String, country: Country) {
        self.name = name
        self.country = country
    }
} 

var country = Country(name: "Canada", capitalName: "Ottawa")
println("\(country.name)'s capital city is called \(country.capitalCity.name)")
// prints "Canada's capital city is called Ottawa" 

The initializer for City is called from within the initializer for Country. However, the initializer for Country cannot pass self to the City initializer until a new Country instance is fully initialized, as described in Two-Phase Initialization.

To cope with this requirement, you declare the capitalCity property of Country as an implicitly unwrapped optional property, indicated by the exclamation mark at the end of its type annotation (City!). This means that the capitalCity property has a default value of nil, like any other optional, but can be accessed without the need to unwrap its value as described in Implicitly Unwrapped Optionals.

Resolving Strong Reference Cycles for Closures

class HTMLElement {

    let name: String
    let text: String?

    @lazy var asHTML: () -> String = {
        if let text = self.text {
            return "<\(self.name)>\(text)</\(self.name)>"
        } else {
            return "<\(self.name) />"
        }
    }

    init(name: String, text: String? = nil) {
        self.name = name
        self.text = text
    }

    deinit {
        println("\(name) is being deinitialized")
    }

} 

var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world")
println(paragraph!.asHTML())
// prints "<p>hello, world</p>” 
paragraph = nil  // the message in the HTMLElement deinitializer is not printed 
class HTMLElement {

    let name: String
    let text: String?

    @lazy var asHTML: () -> String = {
        [unowned self] in
        if let text = self.text {
            return "<\(self.name)>\(text)</\(self.name)>"
        } else {
            return "<\(self.name) />"
        }
    }

    init(name: String, text: String? = nil) {
        self.name = name
        self.text = text
    }

    deinit {
        println("\(name) is being deinitialized")
    }

}

var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world")
println(paragraph!.asHTML())
// prints "<p>hello, world</p>”

paragraph = nil
// prints "p is being deinitialized"   

Optional Chaining

You specify optional chaining by placing a question mark (?) after the optional value on which you wish to call a property, method or subscript if the optional is non-nil.

class Person {
    var residence: Residence?
}

class Residence {
    var numberOfRooms = 1
}

let john = Person()  
let roomCount = john.residence!.numberOfRooms
// this triggers a runtime error

if let roomCount = john.residence?.numberOfRooms { // 返回的是Int?
    println("John's residence has \(roomCount) room(s).")
} else {
    println("Unable to retrieve the number of rooms.")
}
// prints "Unable to retrieve the number of rooms.”

john.residence = Residence()
if let roomCount = john.residence?.numberOfRooms {
    println("John's residence has \(roomCount) room(s).")
} else {
    println("Unable to retrieve the number of rooms.")
}
// prints "John's residence has 1 room(s)."    

The fact that it is queried through an optional chain means that the call to numberOfRooms will always return an Int? instead of an Int.

You cannot set a property’s value through optional chaining.

if john.residence?.printNumberOfRooms() {
    println("It was possible to print the number of rooms.")
} else {
    println("It was not possible to print the number of rooms.")
}
// prints "It was not possible to print the number of rooms.”

if let firstRoomName = john.residence?[0].name {
    println("The first room name is \(firstRoomName).")
} else {
    println("Unable to retrieve the first room name.")
}
// prints "Unable to retrieve the first room name."

If you try to retrieve an Int value through optional chaining, an Int? is always returned, no matter how many levels of chaining are used. Similarly, if you try to retrieve an Int? value through optional chaining, an Int? is always returned, no matter how many levels of chaining are used.

Type Casting

Type casting in Swift is implemented with the is and as operators. These two operators provide a simple and expressive way to check the type of a value or cast a value to a different type.

class MediaItem {
    var name: String
    init(name: String) {
        self.name = name
    }
}

class Movie: MediaItem {
    var director: String
    init(name: String, director: String) {
        self.director = director
        super.init(name: name)
    }
}

class Song: MediaItem {
    var artist: String
    init(name: String, artist: String) {
        self.artist = artist
        super.init(name: name)
    }
}

let library = [
    Movie(name: "Casablanca", director: "Michael Curtiz"),
    Song(name: "Blue Suede Shoes", artist: "Elvis Presley"),
    Movie(name: "Citizen Kane", director: "Orson Welles"),
    Song(name: "The One And Only", artist: "Chesney Hawkes"),
    Song(name: "Never Gonna Give You Up", artist: "Rick Astley")
]
// the type of "library" is inferred to be MediaItem[]

// Use the type check operator (is) to check whether an instance is of a certain subclass type. 

var movieCount = 0
var songCount = 0

for item in library {
    if item is Movie {
        ++movieCount
    } else if item is Song {
        ++songCount
    }
}

println("Media library contains \(movieCount) movies and \(songCount) songs")
// prints "Media library contains 2 movies and 3 songs”

for item in library {
    if let movie = item as? Movie {
        println("Movie: '\(movie.name)', dir. \(movie.director)")
    } else if let song = item as? Song {
        println("Song: '\(song.name)', by \(song.artist)")
    }
}

// Movie: 'Casablanca', dir. Michael Curtiz
// Song: 'Blue Suede Shoes', by Elvis Presley
// Movie: 'Citizen Kane', dir. Orson Welles
// Song: 'The One And Only', by Chesney Hawkes
// Song: 'Never Gonna Give You Up', by Rick Astley     

Casting does not actually modify the instance or change its values. The underlying instance remains the same; it is simply treated and accessed as an instance of the type to which it has been cast.

AnyObject can represent an instance of any class type. Any can represent an instance of any type at all, apart from function types.

let someObjects: AnyObject[] = [
    Movie(name: "2001: A Space Odyssey", director: "Stanley Kubrick"),
    Movie(name: "Moon", director: "Duncan Jones"),
    Movie(name: "Alien", director: "Ridley Scott")
]

for object in someObjects {
    let movie = object as Movie
    println("Movie: '\(movie.name)', dir. \(movie.director)")
}
// Movie: '2001: A Space Odyssey', dir. Stanley Kubrick
// Movie: 'Moon', dir. Duncan Jones
// Movie: 'Alien', dir. Ridley Scott

for movie in someObjects as Movie[] {
    println("Movie: '\(movie.name)', dir. \(movie.director)")
}
// Movie: '2001: A Space Odyssey', dir. Stanley Kubrick
// Movie: 'Moon', dir. Duncan Jones
// Movie: 'Alien', dir. Ridley Scott   
var things = Any[]()

things.append(0)
things.append(0.0)
things.append(42)
things.append(3.14159)
things.append("hello")
things.append((3.0, 5.0))
things.append(Movie(name: "Ghostbusters", director: "Ivan Reitman”))

for thing in things {
    switch thing {
    case 0 as Int:
        println("zero as an Int")
    case 0 as Double:
        println("zero as a Double")
    case let someInt as Int:
        println("an integer value of \(someInt)")
    case let someDouble as Double where someDouble > 0:
        println("a positive double value of \(someDouble)")
    case is Double:
        println("some other double value that I don't want to print")
    case let someString as String:
        println("a string value of \"\(someString)\"")
    case let (x, y) as (Double, Double):
        println("an (x, y) point at \(x), \(y)")
    case let movie as Movie:
        println("a movie called '\(movie.name)', dir. \(movie.director)")
    default:
        println("something else")
    }
}

// zero as an Int
// zero as a Double
// an integer value of 42
// a positive double value of 3.14159
// a string value of "hello"
// an (x, y) point at 3.0, 5.0
// a movie called 'Ghostbusters', dir. Ivan Reitman  

Nested Types

struct BlackjackCard {

    // nested Suit enumeration
    enum Suit: Character {
        case Spades = "♠", Hearts = "♡", Diamonds = "♢", Clubs = "♣"
    }

    // nested Rank enumeration
    enum Rank: Int {
        case Two = 2, Three, Four, Five, Six, Seven, Eight, Nine, Ten
        case Jack, Queen, King, Ace
        struct Values {
            let first: Int, second: Int?
        }
        var values: Values {
        switch self {
        case .Ace:
            return Values(first: 1, second: 11)
        case .Jack, .Queen, .King:
            return Values(first: 10, second: nil)
        default:
            return Values(first: self.toRaw(), second: nil)
            }
        }
    }

    // BlackjackCard properties and methods
    let rank: Rank, suit: Suit
    var description: String {
    var output = "suit is \(suit.toRaw()),"
        output += " value is \(rank.values.first)"
        if let second = rank.values.second {
            output += " or \(second)"
        }
        return output
    }
}

let theAceOfSpades = BlackjackCard(rank: .Ace, suit: .Spades)
println("theAceOfSpades: \(theAceOfSpades.description)")
// prints "theAceOfSpades: suit is ♠, value is 1 or 11”

let heartsSymbol = BlackjackCard.Suit.Hearts.toRaw()
// heartsSymbol is "♡"   

Extensions

Extensions are similar to categories in Objective-C.

Extensions in Swift can:

Add computed properties and computed static properties Define instance methods and type methods Provide new initializers Define subscripts Define and use new nested types Make an existing type conform to a protocol

If you define an extension to add new functionality to an existing type, the new functionality will be available on all existing instances of that type, even if they were created before the extension was defined.

extension SomeType {
    // new functionality to add to SomeType goes here
}

extension SomeType: SomeProtocol, AnotherProtocol {
    // implementation of protocol requirements goes here
}  
extension Double {
    var km: Double { return self * 1_000.0 }
    var m: Double { return self }
    var cm: Double { return self / 100.0 }
    var mm: Double { return self / 1_000.0 }
    var ft: Double { return self / 3.28084 }
}
let oneInch = 25.4.mm
println("One inch is \(oneInch) meters")
// prints "One inch is 0.0254 meters"
let threeFeet = 3.ft
println("Three feet is \(threeFeet) meters")
// prints "Three feet is 0.914399970739201 meters" 

Extensions can add new computed properties, but they cannot add stored properties, or add property observers to existing properties.

struct Size {
    var width = 0.0, height = 0.0
}
struct Point {
    var x = 0.0, y = 0.0
}
struct Rect {
    var origin = Point()
    var size = Size()
}

let defaultRect = Rect()
let memberwiseRect = Rect(origin: Point(x: 2.0, y: 2.0),
    size: Size(width: 5.0, height: 5.0))

extension Rect {
    init(center: Point, size: Size) {
        let originX = center.x - (size.width / 2)
        let originY = center.y - (size.height / 2)
        self.init(origin: Point(x: originX, y: originY), size: size)
    }
}

let centerRect = Rect(center: Point(x: 4.0, y: 4.0),
    size: Size(width: 3.0, height: 3.0))
// centerRect's origin is (2.5, 2.5) and its size is (3.0, 3.0)    
extension Int {
    func repetitions(task: () -> ()) {
        for i in 0..self {
            task()
        }
    }
}

3.repetitions({
    println("Hello!")
    })
// Hello!
// Hello!
// Hello!

//Use trailing closure syntax to make the call more succinct:
3.repetitions {
    println("Goodbye!")
}
// Goodbye!
// Goodbye!
// Goodbye!   

// Structure and enumeration methods that modify self or its properties must mark the instance method as mutating, just like mutating methods from an original implementation.

extension Int {
    mutating func square() {
        self = self * self
    }
}
var someInt = 3
someInt.square()
// someInt is now 9 
extension Int {
    subscript(digitIndex: Int) -> Int {
        var decimalBase = 1
            for _ in 1...digitIndex {
                decimalBase *= 10
            }
            return (self / decimalBase) % 10
    }
}
746381295[0]
// returns 5
746381295[1]
// returns 9
746381295[2]
// returns 2
746381295[8]
// returns 7 
746381295[9]
// returns 0, as if you had requested:
0746381295[9] 
extension Character {
    enum Kind {
        case Vowel, Consonant, Other
    }
    var kind: Kind {
    switch String(self).lowercaseString {
    case "a", "e", "i", "o", "u":
        return .Vowel
    case "b", "c", "d", "f", "g", "h", "j", "k", "l", "m",
    "n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z":
        return .Consonant
    default:
        return .Other
        }
    }
}

func printLetterKinds(word: String) {
    println("'\(word)' is made up of the following kinds of letters:")
    for character in word {
        switch character.kind {
        case .Vowel:
            print("vowel ")
        case .Consonant:
            print("consonant ")
        case .Other:
            print("other ")
        }
    }
    print("\n")
}
printLetterKinds("Hello")
// 'Hello' is made up of the following kinds of letters:
// consonant vowel consonant consonant vowel  

NOTE: character.kind is already known to be of type Character.Kind. Because of this, all of the Character.Kind member values can be written in shorthand form inside the switch statement, such as .Vowel rather than Character.Kind.Vowel.

Protocols

A protocol defines a blueprint of methods, properties, and other requirements that suit a particular task or piece of functionality. The protocol doesn’t actually provide an implementation for any of these requirements—it only describes what an implementation will look like. The protocol can then be adopted by a class, structure, or enumeration to provide an actual implementation of those requirements. Any type that satisfies the requirements of a protocol is said to conform to that protocol.

protocol SomeProtocol {
    // protocol definition goes here
}

struct SomeStructure: FirstProtocol, AnotherProtocol {
    // structure definition goes here
}

class SomeClass: SomeSuperclass, FirstProtocol, AnotherProtocol {
    // class definition goes here
}
protocol SomeProtocol {
    var mustBeSettable: Int { get set }
    var doesNotNeedToBeSettable: Int { get }
}

// Always prefix type property requirements with the class keyword when you define them in a protocol.
protocol AnotherProtocol {
    class var someTypeProperty: Int { get set }
}
protocol FullyNamed {
    var fullName: String { get }
}

struct Person: FullyNamed {
    var fullName: String
}
let john = Person(fullName: "John Appleseed")
// john.fullName is "John Appleseed”

class Starship: FullyNamed {
    var prefix: String?
    var name: String
    init(name: String, prefix: String? = nil) {
        self.name = name
        self.prefix = prefix
    }
    var fullName: String {
    return (prefix ? prefix! + " " : "") + name
    }
}
var ncc1701 = Starship(name: "Enterprise", prefix: "USS")
// ncc1701.fullName is "USS Enterprise"   

Protocols use the same syntax as normal methods, but are not allowed to specify default values for method parameters.

protocol SomeProtocol {
    class func someTypeMethod()
}

protocol RandomNumberGenerator {
    func random() -> Double
}

class LinearCongruentialGenerator: RandomNumberGenerator {
    var lastRandom = 42.0
    let m = 139968.0
    let a = 3877.0
    let c = 29573.0
    func random() -> Double {
        lastRandom = ((lastRandom * a + c) % m)
        return lastRandom / m
    }
}
let generator = LinearCongruentialGenerator()
println("Here's a random number: \(generator.random())")
// prints "Here's a random number: 0.37464991998171"
println("And another one: \(generator.random())")
// prints "And another one: 0.729023776863283"   

If you mark a protocol instance method requirement as mutating, you do not need to write the mutating keyword when writing an implementation of that method for a class. The mutating keyword is only used by structures and enumerations.

protocol Togglable {
    mutating func toggle()
}

enum OnOffSwitch: Togglable {
    case Off, On
    mutating func toggle() {
        switch self {
        case Off:
            self = On
        case On:
            self = Off
        }
    }
}
var lightSwitch = OnOffSwitch.Off
lightSwitch.toggle()
// lightSwitch is now equal to .On  
class Dice {
    let sides: Int
    let generator: RandomNumberGenerator
    init(sides: Int, generator: RandomNumberGenerator) {
        self.sides = sides
        self.generator = generator
    }
    func roll() -> Int {
        return Int(generator.random() * Double(sides)) + 1
    }
}

var d6 = Dice(sides: 6, generator: LinearCongruentialGenerator())
for _ in 1...5 {
    println("Random dice roll is \(d6.roll())")
}
// Random dice roll is 3
// Random dice roll is 5
// Random dice roll is 4
// Random dice roll is 5
// Random dice roll is 4  
protocol DiceGame {
    var dice: Dice { get }
    func play()
}
protocol DiceGameDelegate {
    func gameDidStart(game: DiceGame)
    func game(game: DiceGame, didStartNewTurnWithDiceRoll diceRoll: Int)
    func gameDidEnd(game: DiceGame)
}

class SnakesAndLadders: DiceGame {
    let finalSquare = 25
    let dice = Dice(sides: 6, generator: LinearCongruentialGenerator())
    var square = 0
    var board: Int[]
    init() {
        board = Int[](count: finalSquare + 1, repeatedValue: 0)
        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 delegate: DiceGameDelegate?
    func play() {
        square = 0
        delegate?.gameDidStart(self)
        gameLoop: while square != finalSquare {
            let diceRoll = dice.roll()
            delegate?.game(self, didStartNewTurnWithDiceRoll: diceRoll)
            switch square + diceRoll {
            case finalSquare:
                break gameLoop
            case let newSquare where newSquare > finalSquare:
                continue gameLoop
            default:
                square += diceRoll
                square += board[square]
            }
        }
        delegate?.gameDidEnd(self)
    }
}

class DiceGameTracker: DiceGameDelegate {
    var numberOfTurns = 0
    func gameDidStart(game: DiceGame) {
        numberOfTurns = 0
        if game is SnakesAndLadders {
            println("Started a new game of Snakes and Ladders")
        }
        println("The game is using a \(game.dice.sides)-sided dice")
    }
    func game(game: DiceGame, didStartNewTurnWithDiceRoll diceRoll: Int) {
        ++numberOfTurns
        println("Rolled a \(diceRoll)")
    }
    func gameDidEnd(game: DiceGame) {
        println("The game lasted for \(numberOfTurns) turns")
    }
}

let tracker = DiceGameTracker()
let game = SnakesAndLadders()
game.delegate = tracker
game.play()
// Started a new game of Snakes and Ladders
// The game is using a 6-sided dice
// Rolled a 3
// Rolled a 5
// Rolled a 4
// Rolled a 5
// The game lasted for 4 turns    
protocol TextRepresentable {
    func asText() -> String
}

extension Dice: TextRepresentable {
    func asText() -> String {
        return "A \(sides)-sided dice"
    }
}

let d12 = Dice(sides: 12, generator: LinearCongruentialGenerator())
println(d12.asText())
// prints "A 12-sided dice”

extension SnakesAndLadders: TextRepresentable {
    func asText() -> String {
        return "A game of Snakes and Ladders with \(finalSquare) squares"
    }
}
println(game.asText())
// prints "A game of Snakes and Ladders with 25 squares"    

If a type already conforms to all of the requirements of a protocol, but has not yet stated that it adopts that protocol, you can make it adopt the protocol with an empty extension:

struct Hamster {
    var name: String
    func asText() -> String {
        return "A hamster named \(name)"
    }
}
extension Hamster: TextRepresentable {} 

let simonTheHamster = Hamster(name: "Simon")
let somethingTextRepresentable: TextRepresentable = simonTheHamster
println(somethingTextRepresentable.asText())
// prints "A hamster named Simon" 
let things: TextRepresentable[] = [game, d12, simonTheHamster]

for thing in things {
    println(thing.asText())
}
// A game of Snakes and Ladders with 25 squares
// A 12-sided dice
// A hamster named Simon  
protocol InheritingProtocol: SomeProtocol, AnotherProtocol {
    // protocol definition goes here
}

protocol PrettyTextRepresentable: TextRepresentable {
    func asPrettyText() -> String
}

extension SnakesAndLadders: PrettyTextRepresentable {
    func asPrettyText() -> String {
        var output = asText() + ":\n"
        for index in 1...finalSquare {
            switch board[index] {
            case let ladder where ladder > 0:
                output += "▲ "
            case let snake where snake < 0:
                output += "▼ "
            default:
                output += "○ "
            }
        }
        return output
    }
}

println(game.asPrettyText())
// A game of Snakes and Ladders with 25 squares:
// ○ ○ ▲ ○ ○ ▲ ○ ○ ▲ ▲ ○ ○ ○ ▼ ○ ○ ○ ○ ▼ ○ ○ ▼ ○ ▼ ○    
// Protocol Composition

protocol Named {
    var name: String { get }
}
protocol Aged {
    var age: Int { get }
}
struct Person: Named, Aged {
    var name: String
    var age: Int
}
// any type that conforms to both the Named and Aged protocols 
func wishHappyBirthday(celebrator: protocol<Named, Aged>) { 
    println("Happy birthday \(celebrator.name) - you're \(celebrator.age)!")
}
let birthdayPerson = Person(name: "Malcolm", age: 21)
wishHappyBirthday(birthdayPerson)
// prints "Happy birthday Malcolm - you're 21!" 

You can check for protocol conformance only if your protocol is marked with the @objc attribute, as seen for the HasArea protocol above. This attribute indicates that the protocol should be exposed to Objective-C code and is described in Using Swift with Cocoa and Objective-C. Even if you are not interoperating with Objective-C, you need to mark your protocols with the @objc attribute if you want to be able to check for protocol conformance.

Note also that @objc protocols can be adopted only by classes, and not by structures or enumerations. If you mark your protocol as @objc in order to check for conformance, you will be able to apply that protocol only to class types.

@objc protocol HasArea {
    var area: Double { get }
}

class Circle: HasArea {
    let pi = 3.1415927
    var radius: Double
    var area: Double { return pi * radius * radius }
    init(radius: Double) { self.radius = radius }
}
class Country: HasArea {
    var area: Double
    init(area: Double) { self.area = area }
}
class Animal {
    var legs: Int
    init(legs: Int) { self.legs = legs }
}   

let objects: AnyObject[] = [
    Circle(radius: 2.0),
    Country(area: 243_610),
    Animal(legs: 4)
]

for object in objects {
    if let objectWithArea = object as? HasArea {
        println("Area is \(objectWithArea.area)")
    } else {
        println("Something that doesn't have an area")
    }
}
// Area is 12.5663708
// Area is 243610.0
// Something that doesn't have an area  
// Optional Protocol Requirements 

@objc protocol CounterDataSource {
    @optional func incrementForCount(count: Int) -> Int
    @optional var fixedIncrement: Int { get }
}

@objc class Counter {
    var count = 0
    var dataSource: CounterDataSource?
    func increment() {
        if let amount = dataSource?.incrementForCount?(count) {
            count += amount
        } else if let amount = dataSource?.fixedIncrement? {
            count += amount
        }
    }
}

class ThreeSource: CounterDataSource {
    let fixedIncrement = 3
}

var counter = Counter()
counter.dataSource = ThreeSource()
for _ in 1...4 {
    counter.increment()
    println(counter.count)
}
// 3
// 6
// 9
// 12

class TowardsZeroSource: CounterDataSource {
    func incrementForCount(count: Int) -> Int {
        if count == 0 {
            return 0
        } else if count < 0 {
            return 1
        } else {
            return -1
        }
    }
}

counter.count = -4
counter.dataSource = TowardsZeroSource()
for _ in 1...5 {
    counter.increment()
    println(counter.count)
}
// -3
// -2
// -1
// 0
// 0      

Generics

func swapTwoValues<T>(inout a: T, inout b: T) {
    let temporaryA = a
    a = b
    b = temporaryA
}

var someInt = 3
var anotherInt = 107
swapTwoValues(&someInt, &anotherInt)
// someInt is now 107, and anotherInt is now 3

var someString = "hello"
var anotherString = "world"
swapTwoValues(&someString, &anotherString)
// someString is now "world", and anotherString is now "hello"  
struct Stack<T> {
    var items = T[]()
    mutating func push(item: T) {
        items.append(item)
    }
    mutating func pop() -> T {
        return items.removeLast()
    }
}

var stackOfStrings = Stack<String>()
stackOfStrings.push("uno")
stackOfStrings.push("dos")
stackOfStrings.push("tres")
stackOfStrings.push("cuatro")
// the stack now contains 4 strings
let fromTheTop = stackOfStrings.pop()
// fromTheTop is equal to "cuatro", and the stack now contains 3 strings   

Type Constraints:

func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) {
    // function body goes here
} 
func findIndex<T: Equatable>(array: T[], valueToFind: T) -> Int? {
    for (index, value) in enumerate(array) {
        if value == valueToFind {
            return index
        }
    }
    return nil
}

let doubleIndex = findIndex([3.14159, 0.1, 0.25], 9.3)
// doubleIndex is an optional Int with no value, because 9.3 is not in the array
let stringIndex = findIndex(["Mike", "Malcolm", "Andrea"], "Andrea")
// stringIndex is an optional Int containing a value of 2  

Associated Types:

protocol Container {
    typealias ItemType
    mutating func append(item: ItemType)
    var count: Int { get }
    subscript(i: Int) -> ItemType { get }
}

struct Stack<T>: Container {
    // original Stack<T> implementation
    var items = T[]()
    mutating func push(item: T) {
        items.append(item)
    }
    mutating func pop() -> T {
        return items.removeLast()
    }
    // conformance to the Container protocol
    // 自动推断出 typealias ItemType = T
    mutating func append(item: T) {
        self.push(item)
    }
    var count: Int {
    return items.count
    }
    subscript(i: Int) -> T {
        return items[i]
    }
}  
extension Array: Container {}

Array’s existing append method and subscript enable Swift to infer the appropriate type to use for ItemType, just as for the generic Stack type above. After defining this extension, you can use any Array as a Container.

Where Clauses:

func allItemsMatch<
    C1: Container, C2: Container
    where C1.ItemType == C2.ItemType, C1.ItemType: Equatable>
    (someContainer: C1, anotherContainer: C2) -> Bool {

        // check that both containers contain the same number of items
        if someContainer.count != anotherContainer.count {
            return false
        }

        // check each pair of items to see if they are equivalent
        for i in 0..someContainer.count {
            if someContainer[i] != anotherContainer[i] {
                return false
            }
        }

        // all items match, so return true
        return true

}

var stackOfStrings = Stack<String>()
stackOfStrings.push("uno")
stackOfStrings.push("dos")
stackOfStrings.push("tres")

var arrayOfStrings = ["uno", "dos", "tres"]

if allItemsMatch(stackOfStrings, arrayOfStrings) {
    println("All items match.")
} else {
    println("Not all items match.")
}
// prints "All items match."  

Advanced Operators

let initialBits: UInt8 = 0b00001111
let invertedBits = ~initialBits  // equals 11110000 

let firstSixBits: UInt8 = 0b11111100
let lastSixBits: UInt8  = 0b00111111
let middleFourBits = firstSixBits & lastSixBits  // equals 00111100

let someBits: UInt8 = 0b10110010
let moreBits: UInt8 = 0b01011110
let combinedbits = someBits | moreBits  // equals 11111110

let firstBits: UInt8 = 0b00010100
let otherBits: UInt8 = 0b00000101
let outputBits = firstBits ^ otherBits  // equals 00010001

let shiftBits: UInt8 = 4   // 00000100 in binary
shiftBits << 1             // 00001000
shiftBits << 2             // 00010000
shiftBits << 5             // 10000000
shiftBits << 6             // 00000000
shiftBits >> 2             // 00000001

let pink: UInt32 = 0xCC6699
let redComponent = (pink & 0xFF0000) >> 16    // redComponent is 0xCC, or 204
let greenComponent = (pink & 0x00FF00) >> 8   // greenComponent is 0x66, or 102
let blueComponent = pink & 0x0000FF           // blueComponent is 0x99, or 153    

// 如果允许溢出,在运算符前加&
var willOverflow = UInt8.max
// willOverflow equals 255, which is the largest value a UInt8 can hold
willOverflow = willOverflow &+ 1
// willOverflow is now equal to 0 

var willUnderflow = UInt8.min
// willUnderflow equals 0, which is the smallest value a UInt8 can hold
willUnderflow = willUnderflow &- 1
// willUnderflow is now equal to 255

var signedUnderflow = Int8.min
// signedUnderflow equals -128, which is the smallest value an Int8 can hold
signedUnderflow = signedUnderflow &- 1
// signedUnderflow is now equal to 127  

运算符重载:

struct Vector2D {
    var x = 0.0, y = 0.0
}
// It is said to be infix because it appears in between those two targets.
@infix func + (left: Vector2D, right: Vector2D) -> Vector2D {
    return Vector2D(x: left.x + right.x, y: left.y + right.y)
} 

let vector = Vector2D(x: 3.0, y: 1.0)
let anotherVector = Vector2D(x: 2.0, y: 4.0)
let combinedVector = vector + anotherVector
// combinedVector is a Vector2D instance with values of (5.0, 5.0)

@prefix func - (vector: Vector2D) -> Vector2D {
    return Vector2D(x: -vector.x, y: -vector.y)
}  

let positive = Vector2D(x: 3.0, y: 4.0)
let negative = -positive
// negative is a Vector2D instance with values of (-3.0, -4.0)
let alsoPositive = -negative
// alsoPositive is a Vector2D instance with values of (3.0, 4.0) 

// 复合赋值运算符
@assignment func += (inout left: Vector2D, right: Vector2D) {
    left = left + right
}

var original = Vector2D(x: 1.0, y: 2.0)
let vectorToAdd = Vector2D(x: 3.0, y: 4.0)
original += vectorToAdd
// original now has values of (4.0, 6.0)

@prefix @assignment func ++ (inout vector: Vector2D) -> Vector2D {
    vector += Vector2D(x: 1.0, y: 1.0)
    return vector
}

var toIncrement = Vector2D(x: 3.0, y: 4.0)
let afterIncrement = ++toIncrement
// toIncrement now has values of (4.0, 5.0)
// afterIncrement also has values of (4.0, 5.0)    

It is not possible to overload the default assignment operator (=). Only the compound assignment operators can be overloaded. Similarly, the ternary conditional operator (a ? b : c) cannot be overloaded.

// Equivalence Operators
@infix func == (left: Vector2D, right: Vector2D) -> Bool {
    return (left.x == right.x) && (left.y == right.y)
}
@infix func != (left: Vector2D, right: Vector2D) -> Bool {
    return !(left == right)
} 

let twoThree = Vector2D(x: 2.0, y: 3.0)
let anotherTwoThree = Vector2D(x: 2.0, y: 3.0)
if twoThree == anotherTwoThree {
    println("These two vectors are equivalent.")
}
// prints "These two vectors are equivalent." 

Custom operators can be defined only with the characters / = – + * % < > ! & | ^ . ~.

New operators are declared at a global level using the operator keyword, and can be declared as prefix, infix or postfix:

operator prefix +++ {}

@prefix @assignment func +++ (inout vector: Vector2D) -> Vector2D {
    vector += vector
    return vector
}

var toBeDoubled = Vector2D(x: 1.0, y: 4.0)
let afterDoubling = +++toBeDoubled
// toBeDoubled now has values of (2.0, 8.0)
// afterDoubling also has values of (2.0, 8.0)

Precedence and Associativity for Custom Infix Operators

operator infix +- { associativity left precedence 140 }
func +- (left: Vector2D, right: Vector2D) -> Vector2D {
    return Vector2D(x: left.x + right.x, y: left.y - right.y)
}
let firstVector = Vector2D(x: 1.0, y: 2.0)
let secondVector = Vector2D(x: 3.0, y: 4.0)
let plusMinusVector = firstVector +- secondVector
// plusMinusVector is a Vector2D instance with values of (4.0, -2.0)

A Swift Tour

Functions are actually a special case of closures. (In Swift, functions are just named closures) You can write a closure without a name by surrounding code with braces ({}). Use in to separate the arguments and return type from the body.

Methods on classes have one important difference from functions. Parameter names in functions are used only within the function, but parameters names in methods are also used when you call the method (except for the first parameter). By default, a method has the same name for its parameters when you call it and within the method itself. You can specify a second name, which is used inside the method.

// 错误
let convertedRank = Rank.fromRaw(3)  // convertedRank 的类型是Rank?
let threeDescription = convertedRank.toRaw() // optional type不能直接方法

//正确
let convertedRank = Rank.fromRaw(3)!
let threeDescription = convertedRank.toRaw()  // 3

// 正确
let convertedRank = Rank.fromRaw(3)
let threeDescription = convertedRank!.toRaw()  // 3

// 正确
let convertedRank = Rank.fromRaw(3)
let threeDescription = convertedRank?.toRaw()  // {some 3}

One of the most important differences between structures and classes is that structures are always copied when they are passed around in your code, but classes are passed by reference

结构体中的方法要修改结构体,需要加mutating关键字;类则不用,加了反而错误。

Use extension to add functionality to an existing type, such as new methods and computed properties. You can use an extension to add protocol conformance to a type that is declared elsewhere, or even to a type that you imported from a library or framework.

extension Int: ExampleProtocol {
    var simpleDescription: String {
    return "The number \(self)"
    }
    mutating func adjust() {
        self += 42
    }
}
7.simpleDescription 

You can use a protocol name just like any other named type—for example, to create a collection of objects that have different types but that all conform to a single protocol. When you work with values whose type is a protocol type, methods outside the protocol definition are not available.

let protocolValue: ExampleProtocol = a // a is an instance of SimpleClass, and SimpleClass adopt ExampleProtocol
protocolValue.simpleDescription
// protocolValue.anotherProperty  // Uncomment to see the error

Even though the variable protocolValue has a runtime type of SimpleClass, the compiler treats it as the given type of ExampleProtocol. This means that you can’t accidentally access methods or properties that the class implements in addition to its protocol conformance.

Google Java编程风格指南

Standard

原文:http://www.hawstein.com/posts/google-java-style.html

作者:Hawstein
出处:http://hawstein.com/posts/google-java-style.html
声明:本文采用以下协议进行授权: 自由转载-非商用-非衍生-保持署名|Creative Commons BY-NC-ND 3.0 ,转载请注明作者及出处。

目录

  1. 前言
  2. 源文件基础
  3. 源文件结构
  4. 格式
  5. 命名约定
  6. 编程实践
  7. Javadoc
  8. 后记

前言

这份文档是Google Java编程风格规范的完整定义。当且仅当一个Java源文件符合此文档中的规则, 我们才认为它符合Google的Java编程风格。

与其它的编程风格指南一样,这里所讨论的不仅仅是编码格式美不美观的问题, 同时也讨论一些约定及编码标准。然而,这份文档主要侧重于我们所普遍遵循的规则, 对于那些不是明确强制要求的,我们尽量避免提供意见。

1.1 术语说明

在本文档中,除非另有说明:

  1. 术语class可表示一个普通类,枚举类,接口或是annotation类型(@interface)
  2. 术语comment只用来指代实现的注释(implementation comments),我们不使用“documentation comments”一词,而是用Javadoc。

其他的术语说明会偶尔在后面的文档出现。

1.2 指南说明

本文档中的示例代码并不作为规范。也就是说,虽然示例代码是遵循Google编程风格,但并不意味着这是展现这些代码的唯一方式。 示例中的格式选择不应该被强制定为规则。

源文件基础

2.1 文件名

源文件以其最顶层的类名来命名,大小写敏感,文件扩展名为.java

2.2 文件编码:UTF-8

源文件编码格式为UTF-8。

2.3 特殊字符

2.3.1 空白字符

除了行结束符序列,ASCII水平空格字符(0x20,即空格)是源文件中唯一允许出现的空白字符,这意味着:

  1. 所有其它字符串中的空白字符都要进行转义。
  2. 制表符不用于缩进。

2.3.2 特殊转义序列

对于具有特殊转义序列的任何字符(\b, \t, \n, \f, \r, \“, \‘及\),我们使用它的转义序列,而不是相应的八进制(比如\012)或Unicode(比如\u000a)转义。

2.3.3 非ASCII字符

对于剩余的非ASCII字符,是使用实际的Unicode字符(比如∞),还是使用等价的Unicode转义符(比如\u221e),取决于哪个能让代码更易于阅读和理解。

Tip: 在使用Unicode转义符或是一些实际的Unicode字符时,建议做些注释给出解释,这有助于别人阅读和理解。

例如:

String unitAbbrev = "μs";                                 | 赞,即使没有注释也非常清晰
String unitAbbrev = "\u03bcs"; // "μs"                    | 允许,但没有理由要这样做
String unitAbbrev = "\u03bcs"; // Greek letter mu, "s"    | 允许,但这样做显得笨拙还容易出错
String unitAbbrev = "\u03bcs";                            | 很糟,读者根本看不出这是什么
return '\ufeff' + content; // byte order mark             | Good,对于非打印字符,使用转义,并在必要时写上注释

Tip: 永远不要由于害怕某些程序可能无法正确处理非ASCII字符而让你的代码可读性变差。当程序无法正确处理非ASCII字符时,它自然无法正确运行, 你就会去fix这些问题的了。(言下之意就是大胆去用非ASCII字符,如果真的有需要的话)

源文件结构

一个源文件包含(按顺序地):

  1. 许可证或版权信息(如有需要)
  2. package语句
  3. import语句
  4. 一个顶级类(只有一个)

以上每个部分之间用一个空行隔开。

3.1 许可证或版权信息

如果一个文件包含许可证或版权信息,那么它应当被放在文件最前面。

3.2 package语句

package语句不换行,列限制(4.4节)并不适用于package语句。(即package语句写在一行里)

3.3 import语句

3.3.1 import不要使用通配符

即,不要出现类似这样的import语句:import java.util.*;

3.3.2 不要换行

import语句不换行,列限制(4.4节)并不适用于import语句。(每个import语句独立成行)

3.3.3 顺序和间距

import语句可分为以下几组,按照这个顺序,每组由一个空行分隔:

  1. 所有的静态导入独立成组
  2. com.google imports(仅当这个源文件是在com.google包下)
  3. 第三方的包。每个顶级包为一组,字典序。例如:android, com, junit, org, sun
  4. java imports
  5. javax imports

组内不空行,按字典序排列。

3.4 类声明

3.4.1 只有一个顶级类声明

每个顶级类都在一个与它同名的源文件中(当然,还包含.java后缀)。

例外:package-info.java,该文件中可没有package-info类。

3.4.2 类成员顺序

类的成员顺序对易学性有很大的影响,但这也不存在唯一的通用法则。不同的类对成员的排序可能是不同的。 最重要的一点,每个类应该以某种逻辑去排序它的成员,维护者应该要能解释这种排序逻辑。比如, 新的方法不能总是习惯性地添加到类的结尾,因为这样就是按时间顺序而非某种逻辑来排序的。

3.4.2.1 重载:永不分离

当一个类有多个构造函数,或是多个同名方法,这些函数/方法应该按顺序出现在一起,中间不要放进其它函数/方法。

格式

术语说明:块状结构(block-like construct)指的是一个类,方法或构造函数的主体。需要注意的是,数组初始化中的初始值可被选择性地视为块状结构(4.8.3.1节)。

4.1 大括号

4.1.1 使用大括号(即使是可选的)

大括号与if, else, for, do, while语句一起使用,即使只有一条语句(或是空),也应该把大括号写上。

4.1.2 非空块:K & R 风格

对于非空块和块状结构,大括号遵循Kernighan和Ritchie风格 (Egyptian brackets):

  • 左大括号前不换行
  • 左大括号后换行
  • 右大括号前换行
  • 如果右大括号是一个语句、函数体或类的终止,则右大括号后换行; 否则不换行。例如,如果右大括号后面是else或逗号,则不换行。

示例:

return new MyClass() {
  @Override public void method() {
    if (condition()) {
      try {
        something();
      } catch (ProblemException e) {
        recover();
      }
    }
  }
};

4.8.1节给出了enum类的一些例外。

4.1.3 空块:可以用简洁版本

一个空的块状结构里什么也不包含,大括号可以简洁地写成{},不需要换行。例外:如果它是一个多块语句的一部分(if/else 或 try/catch/finally) ,即使大括号内没内容,右大括号也要换行。

示例:

void doNothing() {}

4.2 块缩进:2个空格

每当开始一个新的块,缩进增加2个空格,当块结束时,缩进返回先前的缩进级别。缩进级别适用于代码和注释。(见4.1.2节中的代码示例)

4.3 一行一个语句

每个语句后要换行。

4.4 列限制:80或100

一个项目可以选择一行80个字符或100个字符的列限制,除了下述例外,任何一行如果超过这个字符数限制,必须自动换行。

例外:

  1. 不可能满足列限制的行(例如,Javadoc中的一个长URL,或是一个长的JSNI方法参考)。
  2. packageimport语句(见3.2节和3.3节)。
  3. 注释中那些可能被剪切并粘贴到shell中的命令行。

4.5 自动换行

术语说明:一般情况下,一行长代码为了避免超出列限制(80或100个字符)而被分为多行,我们称之为自动换行(line-wrapping)。

我们并没有全面,确定性的准则来决定在每一种情况下如何自动换行。很多时候,对于同一段代码会有好几种有效的自动换行方式。

Tip: 提取方法或局部变量可以在不换行的情况下解决代码过长的问题(是合理缩短命名长度吧)

4.5.1 从哪里断开

自动换行的基本准则是:更倾向于在更高的语法级别处断开。

  1. 如果在非赋值运算符处断开,那么在该符号前断开(比如+,它将位于下一行)。注意:这一点与Google其它语言的编程风格不同(如C++和JavaScript)。 这条规则也适用于以下“类运算符”符号:点分隔符(.),类型界限中的&(<T extends Foo & Bar>),catch块中的管道符号(catch (FooException | BarException e)
  2. 如果在赋值运算符处断开,通常的做法是在该符号后断开(比如=,它与前面的内容留在同一行)。这条规则也适用于foreach语句中的分号。
  3. 方法名或构造函数名与左括号留在同一行。
  4. 逗号(,)与其前面的内容留在同一行。

4.5.2 自动换行时缩进至少+4个空格

自动换行时,第一行后的每一行至少比第一行多缩进4个空格(注意:制表符不用于缩进。见2.3.1节)。

当存在连续自动换行时,缩进可能会多缩进不只4个空格(语法元素存在多级时)。一般而言,两个连续行使用相同的缩进当且仅当它们开始于同级语法元素。

第4.6.3水平对齐一节中指出,不鼓励使用可变数目的空格来对齐前面行的符号。

4.6 空白

4.6.1 垂直空白

以下情况需要使用一个空行:

  1. 类内连续的成员之间:字段,构造函数,方法,嵌套类,静态初始化块,实例初始化块。
    • 例外:两个连续字段之间的空行是可选的,用于字段的空行主要用来对字段进行逻辑分组。
  2. 在函数体内,语句的逻辑分组间使用空行。
  3. 类内的第一个成员前或最后一个成员后的空行是可选的(既不鼓励也不反对这样做,视个人喜好而定)。
  4. 要满足本文档中其他节的空行要求(比如3.3节:import语句)

多个连续的空行是允许的,但没有必要这样做(我们也不鼓励这样做)。

4.6.2 水平空白

除了语言需求和其它规则,并且除了文字,注释和Javadoc用到单个空格,单个ASCII空格也出现在以下几个地方:

  1. 分隔任何保留字与紧随其后的左括号(()(如if, for catch等)。
  2. 分隔任何保留字与其前面的右大括号(})(如else, catch)。
  3. 在任何左大括号前({),两个例外:
    • @SomeAnnotation({a, b})(不使用空格)。
    • String[][] x = foo;(大括号间没有空格,见下面的Note)。
  4. 在任何二元或三元运算符的两侧。这也适用于以下“类运算符”符号:
    • 类型界限中的&(<T extends Foo & Bar>)。
    • catch块中的管道符号(catch (FooException | BarException e)。
    • foreach语句中的分号。
  5. , : ;及右括号())后
  6. 如果在一条语句后做注释,则双斜杠(//)两边都要空格。这里可以允许多个空格,但没有必要。
  7. 类型和变量之间:List list。
  8. 数组初始化中,大括号内的空格是可选的,即new int[] {5, 6}new int[] { 5, 6 }都是可以的。

Note:这个规则并不要求或禁止一行的开关或结尾需要额外的空格,只对内部空格做要求。

4.6.3 水平对齐:不做要求

术语说明:水平对齐指的是通过增加可变数量的空格来使某一行的字符与上一行的相应字符对齐。

这是允许的(而且在不少地方可以看到这样的代码),但Google编程风格对此不做要求。即使对于已经使用水平对齐的代码,我们也不需要去保持这种风格。

以下示例先展示未对齐的代码,然后是对齐的代码:

private int x; // this is fine
private Color color; // this too

private int   x;      // permitted, but future edits
private Color color;  // may leave it unaligned

Tip:对齐可增加代码可读性,但它为日后的维护带来问题。考虑未来某个时候,我们需要修改一堆对齐的代码中的一行。 这可能导致原本很漂亮的对齐代码变得错位。很可能它会提示你调整周围代码的空白来使这一堆代码重新水平对齐(比如程序员想保持这种水平对齐的风格), 这就会让你做许多的无用功,增加了reviewer的工作并且可能导致更多的合并冲突。

4.7 用小括号来限定组:推荐

除非作者和reviewer都认为去掉小括号也不会使代码被误解,或是去掉小括号能让代码更易于阅读,否则我们不应该去掉小括号。 我们没有理由假设读者能记住整个Java运算符优先级表。

4.8 具体结构

4.8.1 枚举类

枚举常量间用逗号隔开,换行可选。

没有方法和文档的枚举类可写成数组初始化的格式:

private enum Suit { CLUBS, HEARTS, SPADES, DIAMONDS }

由于枚举类也是一个类,因此所有适用于其它类的格式规则也适用于枚举类。

4.8.2 变量声明

4.8.2.1 每次只声明一个变量

不要使用组合声明,比如int a, b;

4.8.2.2 需要时才声明,并尽快进行初始化

不要在一个代码块的开头把局部变量一次性都声明了(这是c语言的做法),而是在第一次需要使用它时才声明。 局部变量在声明时最好就进行初始化,或者声明后尽快进行初始化。

4.8.3 数组

4.8.3.1 数组初始化:可写成块状结构

数组初始化可以写成块状结构,比如,下面的写法都是OK的:

new int[] {
  0, 1, 2, 3 
}

new int[] {
  0,
  1,
  2,
  3
}

new int[] {
  0, 1,
  2, 3
}

new int[]
    {0, 1, 2, 3}
4.8.3.2 非C风格的数组声明

中括号是类型的一部分:String[] args, 而非String args[]

4.8.4 switch语句

术语说明:switch块的大括号内是一个或多个语句组。每个语句组包含一个或多个switch标签(case FOO:default:),后面跟着一条或多条语句。

4.8.4.1 缩进

与其它块状结构一致,switch块中的内容缩进为2个空格。

每个switch标签后新起一行,再缩进2个空格,写下一条或多条语句。

4.8.4.2 Fall-through:注释

在一个switch块内,每个语句组要么通过break, continue, return或抛出异常来终止,要么通过一条注释来说明程序将继续执行到下一个语句组, 任何能表达这个意思的注释都是OK的(典型的是用// fall through)。这个特殊的注释并不需要在最后一个语句组(一般是default)中出现。示例:

switch (input) {
  case 1:
  case 2:
    prepareOneOrTwo();
    // fall through
  case 3:
    handleOneTwoOrThree();
    break;
  default:
    handleLargeNumber(input);
}
4.8.4.3 default的情况要写出来

每个switch语句都包含一个default语句组,即使它什么代码也不包含。

4.8.5 注解(Annotations)

注解紧跟在文档块后面,应用于类、方法和构造函数,一个注解独占一行。这些换行不属于自动换行(第4.5节,自动换行),因此缩进级别不变。例如:

@Override
@Nullable
public String getNameIfPresent() { ... }

例外:单个的注解可以和签名的第一行出现在同一行。例如:

@Override public int hashCode() { ... }

应用于字段的注解紧随文档块出现,应用于字段的多个注解允许与字段出现在同一行。例如:

@Partial @Mock DataLoader loader;

参数和局部变量注解没有特定规则。

4.8.6 注释

4.8.6.1 块注释风格

块注释与其周围的代码在同一缩进级别。它们可以是/* ... */风格,也可以是// ...风格。对于多行的/* ... */注释,后续行必须从*开始, 并且与前一行的*对齐。以下示例注释都是OK的。

/*
 * This is          // And so           /* Or you can
 * okay.            // is this.          * even do this. */
 */

注释不要封闭在由星号或其它字符绘制的框架里。

Tip:在写多行注释时,如果你希望在必要时能重新换行(即注释像段落风格一样),那么使用/* ... */

4.8.7 Modifiers

类和成员的modifiers如果存在,则按Java语言规范中推荐的顺序出现。

public protected private abstract static final transient volatile synchronized native strictfp

命名约定

5.1 对所有标识符都通用的规则

标识符只能使用ASCII字母和数字,因此每个有效的标识符名称都能匹配正则表达式\w+

在Google其它编程语言风格中使用的特殊前缀或后缀,如name_mNames_namekName,在Java编程风格中都不再使用。

5.2 标识符类型的规则

5.2.1 包名

包名全部小写,连续的单词只是简单地连接起来,不使用下划线。

5.2.2 类名

类名都以UpperCamelCase风格编写。

类名通常是名词或名词短语,接口名称有时可能是形容词或形容词短语。现在还没有特定的规则或行之有效的约定来命名注解类型。

测试类的命名以它要测试的类的名称开始,以Test结束。例如,HashTestHashIntegrationTest

5.2.3 方法名

方法名都以lowerCamelCase风格编写。

方法名通常是动词或动词短语。

下划线可能出现在JUnit测试方法名称中用以分隔名称的逻辑组件。一个典型的模式是:test<MethodUnderTest>_<state>,例如testPop_emptyStack。 并不存在唯一正确的方式来命名测试方法。

5.2.4 常量名

常量名命名模式为CONSTANT_CASE,全部字母大写,用下划线分隔单词。那,到底什么算是一个常量?

每个常量都是一个静态final字段,但不是所有静态final字段都是常量。在决定一个字段是否是一个常量时, 考虑它是否真的感觉像是一个常量。例如,如果任何一个该实例的观测状态是可变的,则它几乎肯定不会是一个常量。 只是永远不打算改变对象一般是不够的,它要真的一直不变才能将它示为常量。

// Constants
static final int NUMBER = 5;
static final ImmutableList<String> NAMES = ImmutableList.of("Ed", "Ann");
static final Joiner COMMA_JOINER = Joiner.on(',');  // because Joiner is immutable
static final SomeMutableType[] EMPTY_ARRAY = {};
enum SomeEnum { ENUM_CONSTANT }

// Not constants
static String nonFinal = "non-final";
final String nonStatic = "non-static";
static final Set<String> mutableCollection = new HashSet<String>();
static final ImmutableSet<SomeMutableType> mutableElements = ImmutableSet.of(mutable);
static final Logger logger = Logger.getLogger(MyClass.getName());
static final String[] nonEmptyArray = {"these", "can", "change"};

这些名字通常是名词或名词短语。

5.2.5 非常量字段名

非常量字段名以lowerCamelCase风格编写。

这些名字通常是名词或名词短语。

5.2.6 参数名

参数名以lowerCamelCase风格编写。

参数应该避免用单个字符命名。

5.2.7 局部变量名

局部变量名以lowerCamelCase风格编写,比起其它类型的名称,局部变量名可以有更为宽松的缩写。

虽然缩写更宽松,但还是要避免用单字符进行命名,除了临时变量和循环变量。

即使局部变量是final和不可改变的,也不应该把它示为常量,自然也不能用常量的规则去命名它。

5.2.8 类型变量名

类型变量可用以下两种风格之一进行命名:

  • 单个的大写字母,后面可以跟一个数字(如:E, T, X, T2)。
  • 以类命名方式(5.2.2节),后面加个大写的T(如:RequestT, FooBarT)。

5.3 驼峰式命名法(CamelCase)

驼峰式命名法分大驼峰式命名法(UpperCamelCase)和小驼峰式命名法(lowerCamelCase)。 有时,我们有不只一种合理的方式将一个英语词组转换成驼峰形式,如缩略语或不寻常的结构(例如”IPv6″或”iOS”)。Google指定了以下的转换方案。

名字从散文形式(prose form)开始:

  1. 把短语转换为纯ASCII码,并且移除任何单引号。例如:”Müller’s algorithm”将变成”Muellers algorithm”。
  2. 把这个结果切分成单词,在空格或其它标点符号(通常是连字符)处分割开。
    • 推荐:如果某个单词已经有了常用的驼峰表示形式,按它的组成将它分割开(如”AdWords”将分割成”ad words”)。 需要注意的是”iOS”并不是一个真正的驼峰表示形式,因此该推荐对它并不适用。
  3. 现在将所有字母都小写(包括缩写),然后将单词的第一个字母大写:
    • 每个单词的第一个字母都大写,来得到大驼峰式命名。
    • 除了第一个单词,每个单词的第一个字母都大写,来得到小驼峰式命名。
  4. 最后将所有的单词连接起来得到一个标识符。

示例:

Prose form                Correct               Incorrect
------------------------------------------------------------------
"XML HTTP request"        XmlHttpRequest        XMLHTTPRequest
"new customer ID"         newCustomerId         newCustomerID
"inner stopwatch"         innerStopwatch        innerStopWatch
"supports IPv6 on iOS?"   supportsIpv6OnIos     supportsIPv6OnIOS
"YouTube importer"        YouTubeImporter
                          YoutubeImporter*

加星号处表示可以,但不推荐。

Note:在英语中,某些带有连字符的单词形式不唯一。例如:”nonempty”和”non-empty”都是正确的,因此方法名checkNonemptycheckNonEmpty也都是正确的。

编程实践

6.1 @Override:能用则用

只要是合法的,就把@Override注解给用上。

6.2 捕获的异常:不能忽视

除了下面的例子,对捕获的异常不做响应是极少正确的。(典型的响应方式是打印日志,或者如果它被认为是不可能的,则把它当作一个AssertionError重新抛出。)

如果它确实是不需要在catch块中做任何响应,需要做注释加以说明(如下面的例子)。

try {
  int i = Integer.parseInt(response);
  return handleNumericResponse(i);
} catch (NumberFormatException ok) {
  // it's not numeric; that's fine, just continue
}
return handleTextResponse(response);

例外:在测试中,如果一个捕获的异常被命名为expected,则它可以被不加注释地忽略。下面是一种非常常见的情形,用以确保所测试的方法会抛出一个期望中的异常, 因此在这里就没有必要加注释。

try {
  emptyStack.pop();
  fail();
} catch (NoSuchElementException expected) {
}

6.3 静态成员:使用类进行调用

使用类名调用静态的类成员,而不是具体某个对象或表达式。

Foo aFoo = ...;
Foo.aStaticMethod(); // good
aFoo.aStaticMethod(); // bad
somethingThatYieldsAFoo().aStaticMethod(); // very bad

6.4 Finalizers: 禁用

极少会去重载Object.finalize

Tip:不要使用finalize。如果你非要使用它,请先仔细阅读和理解Effective Java 第7条款:“Avoid Finalizers”,然后不要使用它。

Javadoc

7.1 格式

7.1.1 一般形式

Javadoc块的基本格式如下所示:

/**
 * Multiple lines of Javadoc text are written here,
 * wrapped normally...
 */
public int method(String p1) { ... }

或者是以下单行形式:

/** An especially short bit of Javadoc. */

基本格式总是OK的。当整个Javadoc块能容纳于一行时(且没有Javadoc标记@XXX),可以使用单行形式。

7.1.2 段落

空行(即,只包含最左侧星号的行)会出现在段落之间和Javadoc标记(@XXX)之前(如果有的话)。 除了第一个段落,每个段落第一个单词前都有标签<p>,并且它和第一个单词间没有空格。

7.1.3 Javadoc标记

标准的Javadoc标记按以下顺序出现:@param@return@throws@deprecated, 前面这4种标记如果出现,描述都不能为空。 当描述无法在一行中容纳,连续行需要至少再缩进4个空格。

7.2 摘要片段

每个类或成员的Javadoc以一个简短的摘要片段开始。这个片段是非常重要的,在某些情况下,它是唯一出现的文本,比如在类和方法索引中。

这只是一个小片段,可以是一个名词短语或动词短语,但不是一个完整的句子。它不会以A {@code Foo} is a...This method returns...开头, 它也不会是一个完整的祈使句,如Save the record...。然而,由于开头大写及被加了标点,它看起来就像是个完整的句子。

Tip:一个常见的错误是把简单的Javadoc写成/** @return the customer ID */,这是不正确的。它应该写成/** Returns the customer ID. */

7.3 哪里需要使用Javadoc

至少在每个public类及它的每个public和protected成员处使用Javadoc,以下是一些例外:

7.3.1 例外:不言自明的方法

对于简单明显的方法如getFoo,Javadoc是可选的(即,是可以不写的)。这种情况下除了写“Returns the foo”,确实也没有什么值得写了。

单元测试类中的测试方法可能是不言自明的最常见例子了,我们通常可以从这些方法的描述性命名中知道它是干什么的,因此不需要额外的文档说明。

Tip:如果有一些相关信息是需要读者了解的,那么以上的例外不应作为忽视这些信息的理由。例如,对于方法名getCanonicalName, 就不应该忽视文档说明,因为读者很可能不知道词语canonical name指的是什么。

7.3.2 例外:重载

如果一个方法重载了超类中的方法,那么Javadoc并非必需的。

7.3.3 可选的Javadoc

对于包外不可见的类和方法,如有需要,也是要使用Javadoc的。如果一个注释是用来定义一个类,方法,字段的整体目的或行为, 那么这个注释应该写成Javadoc,这样更统一更友好。

后记

本文档翻译自Google Java Style, 译者@Hawstein

List Of 10 Funny Linux Commands

Standard

by Rajneesh Upadhyay

Working from the Terminal is really fun. Today, we’ll list really funny Linux commands which will bring smile on your face.

 1. rev

Create a file, type some words in this file, rev command will dump all words written by you in reverse.

# rev  <file name>

Selection_002

Selection_001

 2. fortune

This command is not install by default, install with apt-get and fortune will display some random sentence.

crank@crank-System:~$ sudo apt-get install fortune

Selection_003

Use -s option with fortune, it will limit the out to one sentence.

# fortune -s

Selection_004

3. yes

#yes <string>

This command will keep displaying the string for infinite time until the process is killed by the user.

# yes unixmen

Selection_005

4. figlet

This command can be installed with apt-get, comes with some ascii fonts which are located in /usr/share/figlet.

cd /usr/share/figlet
#figlet -f <font>  <string>

e.g.

#figlet -f big.flf unixmen

Selection_006

#figlet -f block.flf  unixmen
Selection_007

You can try another options also.

5. asciiquarium

This command will transform your terminal in to a Sea Aquarium.

Download term animator
# wget http://search.cpan.org/CPAN/authors/id/K/KB/KBAUCOM/Term-Animation-2.4.tar.gz

Install and Configure above package.

# tar -zxvf Term-Animation-2.4.tar.gz
# cd Term-Animation-2.4/
# perl Makefile.PL && make && make test
# sudo make install

Install following package:

# apt-get install libcurses-perl

Download and install asciiquarium

# wget http://www.robobunny.com/projects/asciiquarium/asciiquarium.tar.gz
# tar -zxvf asciiquarium.tar.gz 
# cd asciiquarium_1.0/
# cp asciiquarium /usr/local/bin/

Run,

# /usr/local/bin/asciiquarium

 asciiquarium_1.1 : perl_008

6. bb

# apt-get install bb
# bb

See what comes out:

Selection_009

 7. sl

Sometimes you type sl instead of ls by mistake,actually  sl is a command and a locomotive engine will start moving if you type sl.

# apt-get install sl
# sl

Selection_012

 8. cowsay

Very common command, is will display in ascii form whatever you wants to say.

apt-get install cowsay
# cowsay <string>

Selection_013

Or, you can use another character instead of com, such characters are stored in /usr/share/cowsay/cows

# cd /usr/share/cowsay/cows
cowsay -f ghostbusters.cow  unixmen

Selection_014or

# cowsay -f bud-frogs.cow Rajneesh
Selection_015

 9. toilet

Yes, this is a command, it dumps ascii strings in colored form to the terminal.

# apt-get install toilet
# toilet --gay unixmen
Selection_016
 toilet -F border -F gay unixmen

Selection_020

toilet  -f mono12 -F metal  unixmen

Selection_018

 10. aafire

Put you terminal on fire with aafire.

# apt-get install libaa-bin
# aafire

Selection_019

That it, Have fun with Linux Terminal!!

Sending Email Using Stored Procedures in Sql Server

Standard
原文:http://www.codeproject.com/Articles/1028172/Sending-Email-Using-Stored-Procedures-in-Sql-Serve

Introduction

A very interesting topic of discussion. We have mail integrated to every application now a days. We integrate email using SMTP settings in the Web.Config in .NET and use the Send method to send mails. Recently, I came across an interesting challenge, where we were to send emails from our SQL Server. Suppose we have to track the successful scheduled sql query execution. We cannot look into the tables it modified every time in order to check if it actually ran through successfully. It would be so nice, if we could get some kind of notification which can help us know about the status of execution. Yes, it is possible to send mails from our sql server using few stored procedures which are actually pre-defined.
Lets learn how:-done

Get Started

Remember we will be using pre defined Stored procedure to send the mails. First of all we need to set up an account with the credentials required by the server to send the mails. Usually the mail is sent through SMTP, Simple Mail Transfer Protocol. The settings would depend on the server your aplication demands. Remember the configuration needs to be valid.
Create a Database Account:-

EXEC msdb.dbo.sysmail_add_account_sp
    @account_name = 'SendEmailSqlDemoAccount'
  , @description = 'Sending SMTP mails to users'
  , @email_address = 'suraj.0241@gmail.com'
  , @display_name = 'Suraj Sahoo'
  , @replyto_address = 'suraj.0241@gmail.com'
  , @mailserver_name = 'smtp.gmail.com'
  , @port = 587
  , @username = 'XXXXXX'
  , @password = 'XXXXXX'
Go

Please use proper credentials and server settings in order to successfully deliver the mails, else they will fail and be queued.
Nextstep is to create a profile which would be used to tconfigure the database mail. The sp would look like below:

EXEC msdb.dbo.sysmail_add_profile_sp
    @profile_name = 'SendEmailSqlDemoProfile'
  , @description = 'Mail Profile description'
Go

This profile would be used in order to set the mail configuration and the emails and sent.
Next step is to map the account to the profile. This will let the profile know, which account credentials it need to work for sending successfully.
That would look like:

-- Add the account to the profile
EXEC msdb.dbo.sysmail_add_profileaccount_sp
    @profile_name = 'SendEmailSqlDemo'
  , @account_name = 'SendEmailSql'
  , @sequence_number = 1
GO

Thus, we are all set to send the successly emails. The mail sending look up snippet would look like below:

EXEC msdb.dbo.sp_send_dbmail
    @profile_name = 'SendEmailSqlDemo2'
  , @recipients = 'suraj.0241@gmail.com'
  , @subject = 'Automated Test Results (Successful)'
  , @body = 'The stored procedure finished successfully.'
  , @importance ='HIGH' 
GO

The stored procedured being used are sometimes vulnerable to not getting executed. So Try catch block and Begin and End Transaction are mandatory in few Stored Procedures.
Lets take an example here,
Suppose we have a SELECT INSERT query using Stored Procedure, so what happens is we are selecting and inserting from 4 tables, lets say
Users | UserLogin | UserEmployment | Departments
For each new screen creation we are manipulating and selecting the users based on their PK and inserting again into the same tables with a different FK, representing the particular screen. The query would look like below:-

BEGIN TRY
  BEGIN TRAN
 INSERT INTO
   dbo.[User]
 SELECT
    us.UserName,
	us.UserAddress,
	us.UserPhone,
    @fkScreenID
 FROM
   dbo.[User] as us
 WHERE
   UserID= @userID
 COMMIT TRAN
    END TRY
   BEGIN CATCH
  ROLLBACK TRAN
  END
  END CATCH  //Similarly for other tables as well we continue. Its is better to add the Try Catch to whole SP Executing Block

Here, when the transaction in case fails, it would move into the Catch block and there we can have the email sending procedure so as to get a notification regarding the success or failure and reason and where it failed. This would be so helpful for any developer.

Troubleshooting Mails

There are also stored procedure to let us know if the mails are successful, failed or remained in the queue. This is fascinating feature. Smile | :) .
To check for the mails which were successfully sent and delivered, we run the below query:

select * from msdb.dbo.sysmail_sentitems

Some of the columns it returns are
Email1
Email2
In the second image you can see we have the sent_status as sent, which states the mail has been successfully sent.

To check for the unsent mails which could not be sent, we run the below query:

select * from msdb.dbo.sysmail_unsentitems

TO check for the failed mails, which will not even be retried to be sent from the queue, we run the below query:-

select * from msdb.dbo.sysmail_faileditems

For more details on the failure along with the reason, the trouble shoot query would look like:

SELECT items.subject,
    items.last_mod_date
    ,l.description FROM msdb.dbo.sysmail_faileditems as items
INNER JOIN msdb.dbo.sysmail_event_log AS l
    ON items.mailitem_id = l.mailitem_id
GO

The results look like below:
Email3

The error description above is like “No Such Host” Error. This error usually comes when we have some smtp server connection settings wrong. We need to troubleshoot that on our own and recheck the settings credentials and then try. If then it does not seem to work, we need to look for the DNS server settings and retry with the configuration again. Nothing to worry for this though..Smile | :)

Conclusion

Thus we discussed here about sending mails from our own SQL using the stored procedures and how helpful they can prove to be. Troubleshooting the errors is very easy here and the set as well.
Exceptions and errors are a part of development which cannot be avoided but handling them is a challenge and developers can easily do that. :)

References

Email Architect
MSDN

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

为什么主引导记录的内存地址是0x7C00?

Standard

作者: 阮一峰

日期: 2015年9月28日

《计算机原理》课本说,启动时,主引导记录会存入内存地址0x7C00。

这个奇怪的地址,是怎么来的,课本就不解释了。我一直有疑问,为什么不存入内存的头部、尾部、或者其他位置,而偏偏存入这个比 32KB 小1024字节的地方?

昨天,我读到一篇文章,终于解开了这个谜。

首先,如果你不知道,主引导记录(Master boot record,缩写为MBR)是什么,可以先读《计算机是如何启动的?》

简单说,计算机启动是这样一个过程。

  1. 通电
  2. 读取ROM里面的BIOS,用来检查硬件
  3. 硬件检查通过
  4. BIOS根据指定的顺序,检查引导设备的第一个扇区(即主引导记录),加载在内存地址 0x7C00
  5. 主引导记录把操作权交给操作系统

所以,主引导记录就是引导”操作系统”进入内存的一段小程序,大小不超过1个扇区(512字节)。

0x7C00这个地址来自Intel的第一代个人电脑芯片8088,以后的CPU为了保持兼容,一直使用这个地址。

1981年8月,IBM公司最早的个人电脑IBM PC 5150上市,就用了这个芯片。

当时,搭配的操作系统是86-DOS。这个操作系统需要的内存最少是32KB。我们知道,内存地址从0x0000开始编号,32KB的内存就是0x0000~0x7FFF

8088芯片本身需要占用0x0000~0x03FF,用来保存各种中断处理程序的储存位置。(主引导记录本身就是中断信号INT 19h的处理程序。)所以,内存只剩下0x0400~0x7FFF可以使用。

为了把尽量多的连续内存留给操作系统,主引导记录就被放到了内存地址的尾部。由于一个扇区是512字节,主引导记录本身也会产生数据,需要另外留出512字节保存。所以,它的预留位置就变成了:


  0x7FFF - 512 - 512 + 1 = 0x7C00 

0x7C00就是这样来的。

计算机启动后,32KB内存的使用情况如下。


+--------------------- 0x0
| Interrupts vectors
+--------------------- 0x400
| BIOS data area
+--------------------- 0x5??
| OS load area
+--------------------- 0x7C00
| Boot sector
+--------------------- 0x7E00
| Boot data/stack
+--------------------- 0x7FFF
| (not used)
+--------------------- (...)

(完)