把《编程珠玑》读薄

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)
+--------------------- (...)

(完)

翠 虚 吟

Standard

[此篇凡一百三十六韵,乃四祖传授五祖白紫清真人者。其中历指旁门异术之不可行,小法闲言之不济事。阐明金液大还丹诀,语精法备,善读者与《还源篇》注合参之,学之甚易,炼必可成,足以醒世破迷。兹并蒙师逐节推详,指示利弊,附列于后。北宗龙门第十二代闵阳林谨识。]

  嘉定壬申八月秋,翠虚道人在罗浮。眼前万事去如水,天地何异一浮沤。吾将脱影归玉阙,遂以金丹火候决。说与琼山白玉赠,使伊深识造化骨。

  [此言已将脱化飞升,必须传道。既得传人,乃有此吟也。]

  道光禅师薛紫贤,付我归根复命篇。指示铅汞两个字,所谓真的玄中玄。辛苦都来只十月,渐渐采取渐凝结。而今通身是白血,已觉四肢无寒热。

  [此述从前自己参访多人,幸遇真师指示铅汞下手用功,今已得效,遂尔现身说法也。]

  后来依旧去参人,勘破多少野狐精。个个不知其一处,都是旁门不是真。恐君虚度此青春,从头—一为君陈。若非金液还丹诀,不必空自劳精神。

  [言得道之后,复去参人,广见世间多少旁门,因教学者必先审知真一之处,自能辟除一切邪径。下文遂将各种空劳精神之术,逐一指明。]

  有如迷者学采战,小心只向房中恋。谓之阴丹御女方,手按尾阎吸气咽。夺人真气补我身,执着三峰信邪见。产门唤作生身处,九浅一深行几遍。轩后彭祖者容成,黄谷寿光赵飞燕。他家别有通宵路,酒肆淫房戏历练。莫言花里遇神仙,却把金蓖换瓦片。树根已朽叶徒青,气海波翻死如箭。

  [此为采生迷死之邪术,明有王法,幽有鬼神,行之无不遭殛,断不可为者。]

  其他有若诸旁门,尚自可结安乐缘。有如服气为中黄,有如守顶为混元。有如运气为先天,有如咽液为灵泉。或者脾边认一穴,执定谓之呼吸根。或者口鼻为玄牝,纳清吐浊为返还。或者默朝高上帝,心目上视守泥九。与彼存思气升降,以此调之夹脊关。与彼闭息吞津唾,谓之玉液金液丹。与彼存神守脐下,与彼作念想眉间。又如运心思夹脊,又如合口拄舌端。丛肩缩头偃脊背,唤作直入玉京山。口为华池舌为龙,唤作神水流潺潺。此普旁门安乐法,拟作天仙岂不难。

  [以上诸法俱末审知真一正诀,故皆谓之旁门,无益身心性命,但自误弄其形神,不致遭殛,故曰尚自可结安乐缘。然已空劳精神,决非仙道,行之积久,或且致病,是亦不可为也。]

  八十放九咽其一,聚气归脐谓胎息。手持念珠数呼吸,冰壶土圭测时刻。或依灵宝毕法行,直勒尾闾咽精液。或参西山会真记,终日无言面对壁。时人虽是学坐禅,何曾月照寒潭碧。时人虽是学抱元,何曾如玉之在石。或言大道本无为,枯木灰心孤默默。或言已自显现成,试问幻身何处得。更有劳形采日月,谓之天魂与地魄。更有终宵服七曜,谓之造化真血脉。更有肘后飞金精,气自腾腾水滴滴。更有太乙含真气,心自冥冥肾寂寂。有般循环运流珠,有般静定想朱橘。如斯皆是养命方,即非无质生灵质。

  [此等小法岂能养得命住?谓之养命方者,时人之说也,间或行之得诀,谨守躯壳而已。或属搬精弄气,或是劳形驰神,或为枯木死灰,皆于真一诀窍不通,执而不化,徒然废事失业,行之一不得当,亦复致病,是亦不可为也。]

  道要无中养就儿,个中自有真端的。都缘简易妙天机,散在丹书不肯泄。

  [言须得妙悟之人及时而投,苟非其人道不虚行也。]

  可怜愚夫自执迷,迷迷相指尽胡为。个股诡怪颠狂辈,坐中摇动颤多时。屈仲偃仰千万状,啼哭叫唤如儿嬉。盖缘方寸失主人,精虚气散神狂飞。一队妄人相唱哄,以此诳俗诱愚痴。不知与道合其真,与鬼合邪徒妄为。一才心动意随动,跳跃颤掉运神机。或曰此是神气来,或曰龙虎争战时,或曰河车千万匝,或曰水火相奔驰。看看摇摆五脏气,一旦脑泻精神羸。当年圣祖留丹决,无中生有作丹基。何曾有此鬼怪状,尽是下士徒阐提。

  [此乃妄人所传,断不可听也。]

  我闻前代诸圣师,无为之中无不为。尽于无相生实相,不假作想并行持。

  [个中真一为真端的,如月照潭,如玉在石,无质生质,无为之为。是以十二活时辰中,只须半个活于,乃无为中之有为。丹道采取交结烹炼都在其中,余只静虚动直,显密相因,沐浴如是,温养亦如是,无为而无不为。仍向伦常日用,以静虚动直为火候,敬以直内,义以方外,活活泼泼,养其无形。自然于无相中生就实相,是为完体,独露真常,有何作想并行持耶?下文遂实指其弊。]

  别有些儿奇又奇,心肾原来非坎离。肝心脾肺肾肠胆,只是空屋旧藩篱。涕唾精津气血液,只可接助为阶梯。精神魂魄心意气,观之似是而实非。何须内观及鉴形,或听灵响视泓池。吞霞饮露服元气,功效不验精神疲。

  [此言作想行持之误,亲以埽清上文所说各种法弊。]

  演说清虚弄炉火,索人投状赍金宝。敢将蛙井藐沧溟,元始天尊即是我。虚收衔号伪神通,指划鬼神说因果。今朝明朝又奏名,内丹外丹无不可。欺贤罔圣味三光,自视福德皆(左忄右麽)(左忄右罗)。招摇徒弟步市廛,醉酒饱肉成群伙。大道原来绝名相,真仙本目无花草。教他戒誓立辛勤,争如汝自辛勤好。一人迷昧犹自可,迷以信迷迷到老。此辈一盲引众盲,共入迷途受忧恼。忽朝福尽业报来,获罪于天无所祷。三元九府录其愆,追魄击魄受冥拷。

  [此言托名丹客法家者,终必自殃也。]

  举世人人喜学仙,几人日月去参玄。各自妄诞自相尚,不务真实为真诠。

  [此指托名讲道以为世俗道贩者,自已不务真实,其说都无实据也。]

  古人好话切须记,功夫纯熟语通仙。言语不通非眷属,功夫不到不方圆。

  [此言求道之士,必先坚持正念,涤虑忘情,功夫纯熟,方能听受师言。受时领悟,藏之于中,头头是道。若粗心负气之徒,虽遇真师口诀,亦复听而不闻,即或闻之,亦如方凿圆枘,格格不相入也。]

  我昔功夫行一年,六脉已息气归根。有一婴儿在丹田,与我形貌亦如然。翻思尘世学道者,三年九载空迁延。依前云水游四海,冷眼看有谁堪传。炷香问道仍下风,勘辨邪正知愚贤。归来作此翠虚吟,犹如果日丽青天。

  [此就现身说法,直指金丹大道,并无年月迁延,故特勘明邪正,以告后人。下文即将其诀明传。]

  埽除未学小伎术,分别火候采药物。只取一味水中金,收拾虚无造化窟。捉将百脉尽归源,脉往气停丹始结。初时枯木依寒岩,二兽相逢如电掣。中央正位产玄珠,浪静风平雷雨歇。片时之间见丹头,软似绵团硬如铁。此是南方赤凤血,采之须要知时节。一般才得万般全,复命归根真孔穴。内中自有真壶天,风物光明月皎洁。龙吟虎啸铅汞交,灼见黄芽并白雪。每当天地交合时,夺取阴阳造化机。卯酉甲庚须沐浴,弦望晦朔要防危。随口随时则斤两,抽添运用在怡怡。十二时中只一时,九还七返这些儿。温养切须当固济,巽风常向坎中吹。行坐寝食总如如,惟恐火冷丹力迟。一年周天除卯酉,九转功夫月用九。至于十月玉霜飞,圣胎圆就风雷吼。一载胎生一个儿,子生孙兮孙又枝。千百亿化最妙处,岂可容易教人知。忘形死心绝尔汝,存亡动静分宾主。朝昏药物有浮沉,水火又符宜检举。真气薰蒸无寒暑,纯阳流溢无生死。有一子母分胎处,妙在层箕斗牛女。

  [此指还丹自采取交结烹炼沐治以至分胎之道。曰扫除,曰只取,曰收拾,曰捉将,曰夺取,一步紧一步,真正口诀上极好替身字义。然不可拘文牵义,合参《还源篇》自知其法不二也。]

  若欲延年救老残,断除淫欲行旁门。果欲留形永住世,除非运火炼神丹。神丹之功三百日,七解七蜕成大还。聚则成形散则气,天上人间总一般。宁可求师安乐法,不可邪淫采精血。古云天地悉皆归,须学无为清静诀。缚住青山万顷云,捞取碧潭一轮月。玄关一窍少人知,此是刀圭甚奇绝。

  [此承上节而言,分胎之际,即是复命开关,已得阳神根基。若遂住手,但冀老而康健,则行上文第五节中诸旁门安乐之法,亦可却病。若留形住世,必须混炼金液还丹,温养三百日功夫,可以迸出阳神。故称为神丹。六为少阳之数,曰解曰蜕者,言当阳神解蜕,方是合取元神,乃为金液大还。下文遂言混炼神丹之道。]

  夜来撞见吕秀才,有一丹诀尤奇哉!却把太虚为炉鼎,括捉乌兔为药材。山河大地发猛火,于中万象生云雷。昔时混沌今品物,一时交结成圣胎。也无金木相间隔,也无龙虎分南北。不问子母及雌雄,不问夫妻共黑白。何人名曰大还丹,太上老君吞不得。老君留与清闲客,服了飞升登太极。更将一盏鸿蒙酒,饵此刀圭壮颜色。

  [此言开关已后,混炼阳神,合就元神,只要把捉得定,片响金液大还,自有猛火烹炼成丹。法诀显露,与《还源篇》合参,自知其妙。]

  任从沧海变桑田,我道壶中未一年。恳知汝心如铁坚,所以口口密相传。妙处都无半句子,神仙法度真自然。速须下手结胎仙,朗吟归去蓬莱天。

  [此篇吟成一百三十余韵,犹云口口密相传。妙处无半句,以明真传正决,不消半句,却非语言文字所能传授。人能坚持正念,炼得心坚如铁,以自然为法度,下手结成胎仙,便可开关混炼成真。全要自体自悟,得而行之,方知其法简易,并非高速难行之事也。又按此篇一十八节。首三节开明道脉正传,须辨邪正。四五六三节历指邪术旁门之不可行。第七节指出真机简易,散在丹书。第八至第十二五节复言小法闲言之不足信受。其第十三节教人先自磨洗,功夫纯熟方能心受、心传。第十四节指明丹道甚易,不必畏难。其第十五节将知药采取以后,至玄关将开以前,所炼玉液丹之法,切实言之,尚是色身上功夫,所谓外药了命是也。其第十七节乃言开关以后炼取金液还丹之道,须兼法色混炼成功,所谓内药了性是也。中间第十六节放将开关作一顿笔,以明分胎以后,正当上下无常、进退无恒之际,听人志向之所在,以是色法生死之交关。至第十八节乃将的传口诀不到半句诗笔透露,令人先将身心克治明净,果然心坚如铁,到得功难措手,一遇师传,即合神仙法度矣!

  总之,学人欲看丹经,须明丹品。凡其书以精血髓气液为药材,用闲咽搐磨存思升降为火候运用者,下品也。以肝心脾肺肾为药材,按年月日时抱元守一为火候运用者,中品也。如石子《还源篇》,取精神魂魄意为药材,以行止坐卧清静自然为火候运用者,上品也。上品简易而易成,中品要妙而可成,下品烦难而难成。

  五祖白真人具述师言,详著《修仙辩惑论》一篇,仰见四祖渡人心切,夙抱点化天下神仙之宏愿,早发露于此篇矣!有志希仙者,当不厌百回读也。]

最上乘天仙修炼法注解

Standard

此法以真心为主,以真炁为用,以三宝为基。外三宝(耳目口)不漏,内三宝(精气神)自合,始得天人(外内)感应,先天一炁自然摄入身中。吾人肉体所有物质,皆属后天阴浊,不能超凡入圣。惟先天纯阳之炁,至灵至妙,杳冥莫测,恍惚难图。虽曰外来,实由内孕。先天(元动力)若不借后天(物质),将何以招摄;后天若不得先天,亦不起变化。此乃无中生有,有里含无;无因有孕之而成象,有因无点之而通灵。仙家妙用,虽着重采取先天一炁以为金丹之母,点化凡躯而成圣体,须知:道法自然,非勉强作为可致也。
第一步
神不离气,气不离神。
呼吸相含,中和在抱。
不搬运,不可执著。
委志清虚,寂而常照。
(注曰:先天一气自虚无中来,二气相交自然神抱于气,气抱于神。先后于天之气,相交相得者,浑如醉梦,自然而然,无一毫作为。吸则气呼则神,神呼气吸,上下往来,复归于本源,炼结成丹为之胎,身心大定无为,而神气自然有所为。委志虚无,不可存想,犹如天地之定静,自然阳升阴降,日往月来而造万物。工夫已久,静而生定,神入气中,气与神合,五行四象,自然攒簇,精凝气结,此坎离交媾。初静之功,纯阴之下,须用阳煅炼,方得真气发生,神明自来。炼自纯熟,工夫静久,自然神气交合。神属南方火,火在卦为离。精属北方水,水在卦为坎。魂属东方木,木在卦为震。魄属西方金,金在卦为兑。意属中央土,土在卦为坤,名曰中宫黄庭。先天玄关为乾,既神与气合,神入气中,自然五行四象攒簇,是为坎离交媾之功。纯阴用火,谓凝神下照坤宫,杳杳冥冥而得真气发生,神明自来,谓一阳生而为复。)
第二步
神守神(坤)宫,真炁自动。
火入水中,水自化炁。
热力蒸腾,恍恍惚惚,似有形状。
此是药物初生,不可遽采。
倘或丝毫念起,真炁遂丧。
(注曰:坤宫乃人身中黄庭,中虚之窍,真气发生之所。此一窍乃祖气之宫,故曰坤宫。坤乃承载万物之谓也。实为产药川源之处,阴阳交媾之所。神守坤宫,要昼夜之间,时刻不离,元神下照,回光静定,逆施造化,拔转天关,大药自此而生,金丹由是而结也。坤宫之火,曰真人之火也。常以神照坤宫煅炼阴阳,精化为气。专心致志,于行住坐卧之间,皆可随意守之,不可散乱。日久而不见其功者,皆因心中杂乱。若煅炼之久,精得火炼,自然化为一气。日久三响,震上泥丸,化为甘露,降下重楼,凝为精液,复归坤位。胚胎元气,渐渐壮旺,神呼气吸,自然含育,周流不息。气脉以停而入静定,大定之中,忽然而动,乃先天一气发生。自坤宫而来,如母恋子,自然感含,神变莫测。听其自然,不可欲速,时至气化,自然见其功效也。天光者神光也。工夫久静,神光照烛,静则神灵,表里透彻,发现于外色象不能碍,爱欲不能障,自然隔墙见物,预知前世矣。
天之轻清在上,地之重浊在下。时至气化,清气上升为天,浊气下凝为地,二气氤氲,化生万物。先天真阳与后天真阴,阴阳混一。忽然定中生动,造化自现,如天地一判,别立乾坤是也。若有一物或明或隐,乃玄珠成象也。此玄珠似乎在外,闭目甚分明,似乎在内,开眼却清白有象。他人不能见,无象独自见分明。故曰无象玄珠。乃是大药之苗始生,其药尚嫩,故不可采。若有妄念,采之必失玄珠,丧却天真至宝,反成魔狂,呼吸乱奔不可救。命宝不可轻弄,其斯之谓。)
第三步
神守坤宫,真炁自聚。
始则凝神于坤炉,煅炼阴精,化为阳炁上升。
次则凝神于乾鼎,阳炁渐积渐厚,晶莹晃耀,上下通明。
此时内真外应,先天一炁从虚无中自然而来。
非关存想,不赖作为。
当先天炁来之候,泥丸生风,丹田火炽。
周身关窍齐开,骨节松散,酥软如绵,浑融如醉。
(注曰:坤宫属地为阴,应人后天有终之形。乾宫属天,应人先天无始之神。乾宫乃虚无玄关一窍,实为造化之源。自无而有谓之造,自有而无谓之化,由造而化。始则受气于虚无一窍而生,终则散精于幻妄图六贼而死,造化循环,不知几万劫。
人禀天地阴阳二气以生,真阳之气在身,为铅为精为坎,真阴之气在心,为汞为神为离,象曰人与天地之气同体。修真之士,既得大药初荫,玄珠成象,而精神壮旺,当此之际,神中之精下交于坎,精中之神上交于离,内则精神交合于内,外则阴阳交合于外,内外明彻,照耀上下,化为一颗明珠,圆陀陀光烁烁,三关升降,上下旋转如轮,周流不息。如斯景象,是内之精神和合,金木交并,水火激发之际。是内有真实,故外应其景象。若非亲造真境,岂能有此哉!先天之气母气,后天之气子气,自然感合,返斯造化之妙,始得药从外来。母气,天气;子气,人气,人能常清净,天地悉皆归。先坤后乾者,又名移鼎换炉,此乃金丹之真窍妙,先天火侯之秘诀。初炼丹时,先须神照坤宫,以火炼药,以神驭气。待真气发生,后守乾宫,悬胎鼎内,结成玄珠,炼成大药,吞入腹中,点化已之阴气,变成乾阳之体,此空中之妙用。时人不悟真空之妙用,不遇至人之传授,道听途说,盲修瞎炼,便向水中求之。水者,杳冥之谓,忘念忘体于杳冥之中,岂不落于顽空乎,必竟终无成丹之理。当以阳燧方诸,水火感通之理,推之自得。阳燧火珠,太阳正宫,以火珠向日燧之。方诸水珠,太阴正宫,以水珠向月珠之。天地悬隔之远,一刻之中,自然得水火也。彼物受气之偏,尚能感通日月,得水火于顷刻之间。何况人为万物之灵,静定之中,岂不感通身中妙化,而结成金丹哉?不知如醉,此是得药之景象。当其玄珠成象,日月交光,正是采药之时,先天适至之侯。当此之际,泥丸自觉风生,从天吹下,灌入玄关两目之中,径通周身,关窍齐开,骨节如断,酸软如绵,心冷如冰,丹田如火,身心欠爽。慎勿恐怖,正是水火烹蒸激发之时,龙虎金木交会之际。少刻三宫气满,二气冲和,尘情尽绝,神气泰定,恍如醉梦,犹如万水万木,互相感激,不知有天地人我。只闻千钟雷呜,万道霞光,灵明内外,琳琅满空,雷轰电击,撼通乾坤。采药归来,这个妙用,如半寸之机发千钧之弩,一旋之水斡万斛之舟。经云,人发杀机,天地反覆,乃真妙之用。又云,月到天心处,风来水面时。又云,杨柳风来面上吹,梧桐月向怀里照。泥丸风清,绛宫月朗,林间嫩风清,一派天音降之句,皆形容先天一气自外而来。)
第四步
一神权分二用,上守玄关,下投牡府。
杳杳冥冥之中,红光闪烁,由脑部降落下丹田。
自己身内真炁,立刻起而翕引。
波翻潮涌,霞蔚云蒸,甘露琼浆,滴滴入腹。
即此便是金液还丹。
须要身如磐石,心若冰壶,方免走失。
(注曰:玄宫即玄关,炼黍米之所。又云,悬胎鼎,朱砂鼎,乾坤鼎,皆异名。前言乾坤,所谓初炼丹,以乾坤为鼎器。先凝神聚于坤位,静中生动,采阴中之阳,名曰兔髓。真气上腾,升上乾宫,动而后静,合阳中之阴,名曰乌肝。二物相融,炼成如意之珠,所谓坎离交媾,癸花发现,真铅初露,先天初现,一阳初动之时。如初三日,月出庚方之象,正所谓活子时。一时分作六侯,二侯得药,四侯别有妙用,此时是得药之初一侯。既得初一侯之药,宜当深入静室,运天然之火,再入兑丁半轮之月现,此时有龙吟虎啸之声。铅汞全在洗心涤虑,沐浴提防。渐过十三日而生乾甲,即十五日,此日圆满乾坤之时。鄞鄂已成,玄牝已立,金花已现,三阳已备之时。月圆满于甲方,应乾之象,恐其金逢望运,正是日月重明之际,再得药之侯,二侯得药。四侯别有妙用之法,为前半月之象,半轮明月之内,有龙吟虎啸之声,要虑险防危之妙用。仙胎已成之后,月到十八,一阴巽方守城,野战之妙用。次炼二阴,下弦二十三,艮地洗心沐浴之妙用。炼尽三阴,阳神出现,提防固济之妙用。此名前三三后三三,四侯之妙用也,二侯得药之理。神守玄宫,意迎牝府,此二句是采药之口诀。当其玄宫之中,至精发生,真铅之气,发现一轮明月之象,真汞之水,发现一轮红日之象。日月之中,各发金花二朵,壮如丹山,金红赤色。斯时正不老不嫩,急急采取,何采何取,诀曰,只是意迎牝府,神意相合,先天自得。恍恍惚惚,杳杳冥冥,一点红光,闪入下元,交会真阴,阴乃翕然凑合,阴乃抱阳,阳乃激阴,阴阳激发,海浪泛涌,自太玄关至尾闾夹脊,过玉枕化为金液,琼浆吞入腹内,香甜清爽,耳听鼓声,万颗雷呜,钧天妙药,非琴非瑟,非笛非箫,别是一般妙音,似寒泉漱玉,似金磬摇空,似秋蝉拽绪,似风鼓青松,非常之异。琳琅振响,有群鸦齐噪之声,众鸟频伽之韵,口涵目惊,心怜意悦,诚为极乐之邦,实乃天宫妙境。尘寰俗客,如瞽如聋。身心清净,百关和畅,万孔生春,遍体发出万道霞光,现一圆光,内有婴儿之象,乃阳神出现也。全在防危虑险,不可远离。)
第五步
神守黄庭,仙胎自结。朝朝暮暮,行住坐卧,不离这个。
十月胎圆,玄珠成象。
三年火足,阴魄全销。
身外有身,显则神彰于气。
形中无质,隐则气敛于神。
九载功完,形神俱妙。百千万劫,道体长存。
(注曰:黄房即黄庭宫,故为乾之下坤之上,规矩之中。金胎即仙胎,金乃坚刚不坏之物,此乃人之元神。此元神不坏不朽,清净妙用之体,如金之坚,如刚之利,净如琉璃,光如满月。存不亏明,因一念之妄,缘于幻化。得返还之丹道,要炼有合无,投黑结红而成仙胎,返本来之真常,合元始之妙用。金胎自成,规中之妙,以神守之。黄房之中,一意不散,十二时中,念兹在兹,含光藏耀,敛视收听,绵绵若存,不可须臾离。如鸡抱卵,如龙养珠。龙养项下之珠,心意不忘,精神感化,其珠有光,生光既久,珠成小龙,飞腾太空,或收或放,时人见之,是为龙象,乃龙之神。神全变化,兴云致雨,脱骨飞腾,是谓神龙。所以能大能小,可潜可显,动则裂泰山发洪浪,兴云起雾,击电轰雷。静则隐藏渊泉,是阳灵之物。金丹之道,学天仙者,亦如此理。初则抱元守一,养先天黍米,元神妙珠。存养之久,自然元神黍米,劫劫相会,渐渐相化。新月娥眉,次而半轮上弦,渐至满月之圆。自有金光发现,日月合壁,铅汞相投,结成仙胎。温养三年,婴儿老成,直至九年,功圆行满,阴滓尽消,一神可以化百神万神,形神俱妙,出有入无,炼神与太虚同体,返乎无极之真道,合乎元始之妙境。观天地在玄妙中,如太仓一粒黍,太虚一片云耳。有何五行拘系也,有何阴阳变化也,于斯天地,由吾提挈,阴阳由吾把握,永无终始,浩劫度存,与道合真,神哉神哉。)

内功经

Standard

内功经

内功之传,脉络甚真,不知脉络,勉强用之,则无益而有损。

卷一内功篇

 

学医道者,不可不明乎经络,何况习内功乎?若不明脉络,犹习射而操弓矢,其不能也决矣。能内景遂道,返观而以察之,则体用兼备矣。

前任后督,气行滚滚,井池双穴,发劲循循。气纳丹田,冲起命门,引督脉过尾闾,由脊中直上泥丸,下人中龈交,追动性元,引任脉降重楼,而下返气海。两脉上下,旋转如园,前降后升,络绎不绝也。井者,足少阳胆经,肩上陷中之肩井穴也。池者,手阳明大肠经,屈时横纹头陷中之曲池穴也。大肠经所入合土,土生金,手足少阳,足阳明,阳维之会,连入五脏,周身发劲之所也。

龟尾升气,丹田炼神,气下于海,光聚天心。龟尾者,长强穴也。谷道轻提,真气自然上升矣。丹田者,冲脉(上起百会,下达会阴),带脉(腰一周之脉)之中,脐下内部也。为男子精室,女子胞宫所在,调整呼吸,固精健肾,练神之所也。小腹正中为气海,额上正中为天心,之气充于内,形光于外也。

既明脉络,次观格式。格式者,入门一定之规也。不明此,即脉络亦空谈耳。头正而起,肩平而顺,胸函而闭,背平而正。正头起项虚领颈,壮面神顺颌微收,松肩垂肘肩自活,小腹放松胸须函。背平身微有收敛之形,此式中之真窍也。

足坚而稳,膝曲而伸,裆深而藏,肘开而张。足既动步,膝须曲而伸,伸而曲。膝用力内扣,前阴缩,故步能坚而稳,而裆亦开矣。肘开张,两侧肋骨由胆脏气脉带动之,而肋亦开矣。

既明格式,下言气窍:气调而匀,劲松而紧,出气莫令耳闻,劲必先松而后紧,缓缓行之,久久功成。盖息从心起,心静息调。又云:肺金不清,必先调息。呼则形松似落雁,吸则意紧随气行,此即内三合之形松意紧,进而心血调融,神态安静,固精健肾,祛病延年。

先吸后呼,一出一入;先提后下,一升一伏,内收丹田,气气归根。吸入呼出,勿使有声。呼吸出入,气交错也。调息匀细,真气也。提者,吸气之时,存想真气上升至顶也;下者,真气归纳于丹田也。升者,气随意上升也;伏者,觉周身之气渐坠于丹田,龙蛰虎卧潜伏之。

下收谷道,上提玉楼,或立或坐,吸气于喉,以意送下,渐至底收。收者,谷道轻提,防气之泄也。提者,耳后高骨玉楼穴也。正头起项,使气往来无阻碍也。不拘坐立,气至喉者,以肺摄心透前胸也。气虽聚于丹田,存想沉至底,方为妙也。底者,涌泉穴也。

升有升路,肋骨齐举,降有降所,气吞俞口。气升于两肋,骨缝极力开展,向上举之,自然得窍。降时必自俞口,以透入前心,方明真路。

既明气窍,再谈劲诀。曰通,劲之顺也。曰透,骨之速也。通、透、往来无阻也。伸劲拨力以和缓,柔软之意也。曰穿,劲之连也。曰贴,劲之络也。

穿、贴,横竖连络也。伸劲拨力以刚坚,凝结之意也。曰松,劲之涣也。曰悍,劲之萃专也。松涣者,柔之极也,养精蓄锐之意也。悍萃者,刚之极也。松如绳之系,悍如冰之清,气血结聚之谓也。

曰合,劲之一也。曰坚,劲之专也。合者,周身之一也。坚者,横竖斜缠之谓也。按肩以练步,逼臀以坚膝,圆裆以壮胯,提胸以下腰。

按肩者,收肩井穴,劲沉至涌泉穴。逼臀者,两臀极力贴住。圆裆者,由内向外极力挣横也。提胸者,起前胸也。提骸以正项,贴背以转手,松肩以出劲。

提骸者,后脑骨虚灵上顶,骸自提也。贴背者,两背骨用力贴住,觉其劲自脐下而出,自六腑向外转,至手骨而回也。松肩者,出劲之时,将肩井穴之劲,软意松开,自无阻碍矣。

曰横劲,曰竖劲,变之分明,横以济竖,竖以横用。竖者,肩至足底;横者,两臂及手也。以身说则竖者,自督脉至两肩穴也。横者,自六腑转于手骨背也。自裆至足底,自膝至于臀,以腿而言之也。

五气转元,周而复始,四肢元首,收纳甚妙。吸气纳于丹田升真气于顶,复自俞口降于丹田,又一运真气,自裆下于足底,复上自外胯升于丹田,二运真气自背胳膊里出手,复自六腑转于丹田。一升一降,一下一起,一出一入,融洽不悖,周滚不息,久久用之,好处参悟甚多。

以上劲诀既详,下言调气之方。每日清晨,或坐或立,闭目钳口,细调呼吸,一出一入经鼻孔,而少时气定,遂吸气一口,但吸气时须默想真气,自涌泉穴升至会阴,分向两肋,自两肋升于前胸,由前胸升于脑后,渐升入泥丸百会穴。降气时须默想真气由泥丸降至印堂,自鼻至喉,喉至脊背,脊背透至前心,前心沉至丹田,丹田气足,自能复从尾闾长强近于脊背,上升泥丸,周而复始,如环无端,纯乎天地循环之理也。

 

 

 

卷二纳卦篇

 

 

乾三头肩法乎天乾,取其刚健纯粹。坤三足膝法乎地坤,取其镇静厚载。评曰:

阴阳合德,气发四体,备乾健坤顺之德,当其静也,阴阳所存,无迹可见,及其动也。看似至柔,其实至刚,刚柔互运,无端可寻。是谓阴阳合德,故取诸乾坤也。

凡一出手,先视虎口穴,前颌用力,正平提起,后脊背用力塌下,真气来时直冲尻尾长强穴,谷道着力提住,由脊背上升至顶,由百会转过昆仑下印堂,贯两目而至鼻,其气欲从鼻孔汇时,即便吸入丹田,两耳下各三寸六分之象眼穴用力向下截住,合周身全局之力守之,用之久久自知其妙也。

凡一用步,两外虎眼极力向内,两内虎眼极力向外,委中大筋,竭力要直,两端骨复竭力要曲,四面相交,合周身之力,向外一扭,则涌泉之气,自能从中透出矣。

巽三肩背宜于松活,乃巽顺之意。兑三裆胯宜于靠紧,须现兑泽之情。塌肩井穴,须将肩顶头正直落下,与此肩骨相合。曲池穴比肩顶骨略低半寸,手腕直与眉齐,背骨遂极力贴住,此是竖劲,不是横劲。以竖则实,以横则虚。下肩井穴,自背骨直至足底,故谓之竖。右臂则收左臂之劲,自骨底以意透于右臂,直达两扇门穴,故谓之横。两劲并用而不乱,元气方能升降自如,而巽顺之意明矣。

艮三震三艮象曰:时行则行,时止则止,其义深哉!胸欲竦起,艮山相似,肋有呼吸震动莫测。评曰:震上艮下曰颐,为平为止。手止,人震动也;足止,中开胸自裆皆虚如四阴,则内刚外柔,如颐中有物能噬嗑,则物不能阻隔矣。取诸颐小过,艮下震上,雷在山上震惊百里,令人不及掩耳。足下屹立如山,震为足,为动也。

肋者,协也,鱼腮也。胸虽出而不高,虽闭而不束,虽张而不开,此中玄妙,难从口授。用力须以意出,以气腾,以神足,则为合式,非出骨肉之劲也。用肋一气之呼吸,为开闭。以手之出入为开闭,以身之纵横为开闭。高步劲在于足,中步劲在于肋,下步劲在于背,自然之理也。

坎三离三坎离之卦,乃身内之义也。可以意会,不可言传。心肾为水火之象,水宜升,火宜降,两相既济,水火相交,真气乃萃,精神渐长,聪明且开,岂但劲乎!

练神练气,返本还元,天地交泰,水升火降,头足上下,交接如神。

 

 

卷三神运篇

 

 

 

总诀四章静生光芒,动则飞腾,气腾形随,意动神固,神帅气,形随气腾。练形而能坚,练精而能实,练气而能壮,练神而能轻,固形气以为纵横之本,萃精神以为飞腾之基。

第一章神运之体先明进退之势,后究动静之根,进因伏而后起,退才合而即动,以静为本,身虽疾而心自静,静之妙当明内外呼吸之间。故形气胜能纵横,精神敛能飞腾。

纵横者,劲之横竖。飞腾者,气之深微。第二章节神运之式击敌者有用神、用气、用形之迟速不同,被击者有仆也、怯也、索也,深浅之异。

以神击神,身未动而先入。以气击气,手方动而不畏。以形击形,目到后乃胜。神受神攻,神伤而索于胆。气受气攻,气伤而怯于心。形受形攻,形伤而仆于地。

第三章神运之用纵横者,肋中开合之式。飞腾者,丹田呼吸之间。进退者,随手之出入;动静者,任气之来去自然。气欲露而神欲敛,身欲稳而步宜坚。既不失之于轻,复不失之于重。探如鹰隼之飞,疾如虎豹之强。

第四章神运之体用山有撼则崩,树无根必倒,水无源必涸,工夫亦然。欲明神运,必须内功十二大劲。周身全局合一方可用,否则不惟无益,而且有损。练时必须骑马式、稳住周身全局,一呼则纵,一吸则敛,纵起两足亦起,敛时两足亦齐落,此法永不可易。然用劲又因敌布阵,当有高低、上下,远近、迟速、虚实、大小变化不一。刚柔动静之间,成败得失之际,纯在斯也。欲善用劲,须动步不动心,动身不动气。心静而步坚,气静而身稳,由静而精,自得飞腾变化矣。

盖知静之为静,静亦动也;知动之为动,动亦静也。是以善用于神运者,神缓而眼疾,心缓而手疾,气缓而步疾。盖因外疾而内缓,外柔而内刚,和体用之妙也。是知所贵者,以柔用刚,方是真刚;以缓用疾,方是真疾。此中动静奥妙之用,得之于象外,非可以形亦求之也。须要深究详参,久而久之,神运之法,妙理自然悟矣。

神动既明,可言十二大劲:一曰、底练稳步如山二曰、紧膝曲腿如柱三曰、裆胯内外凑集四曰、胸背刚柔相济五曰、头颅正直撞敌

六曰、三门坚肩贴背七曰、二门横时用肘八曰、穿骨破彼之劲九曰、坚骨封彼之下十曰、内掠敌彼之里十一曰、外格敌彼之外十二曰、撩攻上下内外如一

 

 

 

卷四地龙篇

 

 

地龙真诀,利在底收,全身练地,强固精神。伸可成曲,住亦能能行,曲如伏虎,伸比腾龙,行亦无迹,伸曲潜踪。身坚如铁,法密如龙。翻猛虎豹,转疾隼鹰。倒分前后,左右分明,门有变化,法无定形。前攻用手,二三门间。后攻用足,撞膝逼攻。远则追击,近则接迎。大胯着地,侧身局成,仰倒若坐,尻尾学凭,高低任意,远近纵横。

软能制敌最堪夸,变化无穷总一家,好处全凭能借力,当场着意莫轻拿。软中求硬好、缩小绵软巧,总之九节进,言明方知晓。掌拳肘和腕,肩胯膝足腰,身眼手法步,总是武艺高,掌拳时正进,慢慢往里找。

——————————-

内功之传,脉络甚真;前任后督,行气滚滚;井池双穴,了劲循循。千变万化,不离乎本,得其奥妙,方叹无垠。龟尾升气,丹田练神,气下于海,光聚天心
   既明脉络,次观格式;头正而起,肩平而顺,胸出而闭,背平而正,足坚而稳,膝屈而伸,裆深而藏,肋平而张。
   既明格式,下言气窍:气调而匀,劲松而紧,缓缓行之,久久功成。先吸后呼,一出一入;先提后下,一升一伏;内收丹田,气之归宿,吸入呼出,勿使有声。下收谷道,上提玉楼,或坐或立,吸气于喉,发意送下,渐至底收。升的升路,肋骨齐举;降的降所,气吞俞口。
   既明气窍,再详劲诀:通、透、穿、贴、松、悍、合、坚。曰通,劲之顺也;曰透,劲之速也;曰穿,劲之连也;曰贴,劲之络也;曰松,劲之涣也;曰悍,劲之萃也;曰合,劲之一也;曰坚,劲之转也。
   按肩以练步,逼臀以坚膝,圆裆以坚胯,提胸以下腰,提颏以正项,贴背以转手,松肩以出劲。曰横劲,曰坚劲,变之分明,横以坚济,坚以横用
   五气朝元,周而复始,四肢元首,收纳甚妙。练神练气,返本还原,天地交泰,水升火降,头足上下,交接如神。静生光芒,动则飞腾,气胜形随,意劲神同。以神帅气,以气帅形,形随气腾。
   劲诀既详,下言调气:每日清晨,或坐或立,闭目钳口,细调呼吸,一出一入,皆从鼻孔,而少时气定,遂吸气一口,默想真气自涌泉发出,升于两肋,自两肋升于前胸,自前胸升于耳后,渐升于泥丸百会穴;降气时,默想真气由泥丸降至印堂,至鼻,至喉,至脊背,透至前心,沉于丹田。丹田气足,自能复于尾闾,达于脊背,上升泥丸。周而复始,从乎天地循环之理也。      2、纳卦经
   头颈效法乎乾,取其刚坚纯粹。
   足膝效法乎坤,取其镇静厚载