<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>cnDenis的笔记</title><link>https://blog.cndenis.com/index.html</link><description>Recent content on cnDenis的笔记</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><lastBuildDate>Sat, 16 Sep 2023 00:00:00 +0000</lastBuildDate><atom:link href="https://blog.cndenis.com/index.xml" rel="self" type="application/rss+xml"/><item><title>分组密码的工作模式</title><link>https://blog.cndenis.com/Python/2023/09/blog_cipher_mode_of_operation.html</link><pubDate>Sat, 16 Sep 2023 00:00:00 +0000</pubDate><guid>https://blog.cndenis.com/Python/2023/09/blog_cipher_mode_of_operation.html</guid><description>&lt;p&gt;了解一点密码学的都知道, 对称密码算法只有一个密钥, 加密解密都用同一个密钥. 最常见的AES就属于对称密码.
写成伪代码就是 密码 = AES加密(密钥, 明文). 但是到实际应用的代码的时候, 就会发现AES的加解密库还要求提供其他的一些参数:
其中工作模式(mode)是必填, 这参数是啥, 本文就讨论一下这个问题.&lt;/p&gt;
&lt;h2 id="电子密码本ecb"&gt;电子密码本(ECB)
&lt;/h2&gt;&lt;p&gt;AES是分组密码, 也就是明文要先分组, 每组128bit, 然后再对每一组明文加密, 输出密文. 按着这个最基本的思想,
就得到第一种工作模式, 电子密码本(ECB)模式.&lt;/p&gt;
&lt;p&gt;ECB模式加密步骤如下&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;明文分组为P1, P2, P3&amp;hellip;&lt;/li&gt;
&lt;li&gt;对每一组明文分别用密钥进行加密, 得到密文C1, C2, C3&amp;hellip;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;ECB模式是最简单的, 但它也存在一个明显的问题: 相同的明文分组会生成相同的密文分组.
这在一些场景中可以通过分析密文就可以道到原始明文的一些规率, 例如说包含较多单一色块的图片,
用ECB模式加密后仍然可以辨认出原始图片的一些轮廓.&lt;/p&gt;
&lt;h2 id="密码分组链接cbc"&gt;密码分组链接(CBC)
&lt;/h2&gt;&lt;p&gt;为了解决ECB的这个问题, 研究人员提出了密码分组链接(CBC)模式. 因为加密算法是个确定性的算法,
也就是不包含随机性的, 相同输入必定产生相同输出的. 要对相同明文产生不同的密文, 就需要引入随机的参数,
这个参数就是初始向量(iv).&lt;/p&gt;
&lt;p&gt;CBC模式加密步骤如下&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;明文分组为P1, P2, P3&amp;hellip;&lt;/li&gt;
&lt;li&gt;生成一个128bit(等于一个分组的大小)的随机数作为iv&lt;/li&gt;
&lt;li&gt;iv 与 P1 异或, 得到 M1&lt;/li&gt;
&lt;li&gt;使用密钥加密M1, 得到密文C1&lt;/li&gt;
&lt;li&gt;C1 与 P2 异或, 得到 M2&lt;/li&gt;
&lt;li&gt;使用密钥加密M2, 得到密文C2&lt;/li&gt;
&lt;li&gt;重复5和6的步骤, 直到所有明文使用完毕&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;CBC第一个分组使用了一个随机的iv进行异或计算, 然后再加密, 只要每次使用的iv都不一样,
得到的第一组密文就是不一样的, 然后后面每一个分组的明文都先与上一组的密文做了异或,
再进行加密, 这样由iv所带来的随机性就像链条一样一组一组往后传播, 使得每一组密文都变得不可预测.
这就是&amp;quot;密码分组链接&amp;quot;这个词的由来.&lt;/p&gt;
&lt;p&gt;CBC模式的密文解密不只需要密钥, 还需要知道iv才可以完整解密, 因此, 通信双方需要先约定iv的值.
iv通常不需要保密, 可以直接明文传输. 如果是对磁盘文件做加密, iv也需要保存下来.&lt;/p&gt;
&lt;h2 id="输出反馈ofb模式"&gt;输出反馈(OFB)模式
&lt;/h2&gt;&lt;p&gt;AES是分组密码, 加密的数据长度必须要是规定的分组长度的整倍数才能进行, 数据并不总能填满一个分组的,
需要对不满一个分组的数据做加密. 这种情况下有两种解决方案, 一种是对数据进行填充,
把长度填充到规定的分组长度的整倍数. 另一种是用序列密码, 序列密码是对数据的每一位做加密,
对数据长度没有要求的. 输出反馈(OFB)模式就是把分组密码作为序列密码使用的一种方式.&lt;/p&gt;
&lt;p&gt;OFB模式加密步骤如下:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;明文分组为P1, P2, P3&amp;hellip;&lt;/li&gt;
&lt;li&gt;生成一个128bit(等于一个分组的大小)的随机数作为iv&lt;/li&gt;
&lt;li&gt;使用密钥加密iv, 得到加密序列E1&lt;/li&gt;
&lt;li&gt;E1 与 P1 异或, 得到密文C1&lt;/li&gt;
&lt;li&gt;使用密钥加密E1, 得到加密序列E2&lt;/li&gt;
&lt;li&gt;E2 与 P2 异或, 得到密文C2&lt;/li&gt;
&lt;li&gt;重复步骤5和6, 直到明文使用完毕&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;OFB模式的是以iv做为随机性的种子, 生成一段与明文等长的加密序列, 然后逐个bit与明文做异或,
得到与明文等长的密文. 从这个过程可以看出, 加密序列的生成与明文是无关的, 只取决于iv,
因此, 加密序列可以预先生成, 而不必等待明文准备好.&lt;/p&gt;
&lt;p&gt;OFB模式适合于流加密, 因为加密序列可以预先生成, 明文每出现一个bit, 立即就可以加密一个bit,
而且密文和明文长度完全相等. OFB模式每一个bit的加密结果都对其他bit没有影响, 在传输有可能出错的场合,
这个特性是很有用的. 例如如音视频流的加密, 如果密文传输过程中有少数的几个bit出错, 在解密后,
这些错误只会影响明文对应的那几个bit, 其他数据不受影响, 整个音视频还是基本能用的.&lt;/p&gt;
&lt;p&gt;但是在另外的一些场合, 人们可能会希望一个bit的错误会引起明显的后果, 密文反馈(CFB)模式就有这种效果.&lt;/p&gt;
&lt;h2 id="密文反馈cfb模式"&gt;密文反馈(CFB)模式
&lt;/h2&gt;&lt;p&gt;CFB模式和OFB模式一样, 是把分组密码作为序列密码使用的一种方式.&lt;/p&gt;
&lt;p&gt;CFB模式加密步骤如下:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;明文分组为P1, P2, P3&amp;hellip;&lt;/li&gt;
&lt;li&gt;生成一个128bit(等于一个分组的大小)的随机数作为iv&lt;/li&gt;
&lt;li&gt;使用密钥加密iv, 得到加密序列 E1&lt;/li&gt;
&lt;li&gt;使用 E1 与 P1 异或, 生成密文 P1&lt;/li&gt;
&lt;li&gt;使用密钥加密P1, 得到加密序列 E2&lt;/li&gt;
&lt;li&gt;使用 E2 与 P2 异或, 生成密文 P2&lt;/li&gt;
&lt;li&gt;重复步骤5和6, 直至所有明文使用完毕&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;OFB的加密序列生成不依赖明文, 可以无限长度预先生成, CFB则相反, 每一组加密序列的生成都依赖于上一组密文,
因此需要依赖上一组的明文, 不能预先生成无限长度的加密序列, 而只能生成一个分组的加密序列.&lt;/p&gt;
&lt;p&gt;在最后一个分组, 由于步骤5的加密序列已经生成好, 步骤6仅仅是一个简单的按位异或,
因此只需要截取与最后一组明文相同长度的加密序列与明文进行计算即可, 不需要填充,
所以CFB密文长度也是和明文等长的.&lt;/p&gt;
&lt;p&gt;CFB模式的每分组的密文会用于下一个分组的密钥生成, 因此如果密文的某一个bit错误, 由于AES算法的扩散性,
就会导致下一个分组的解密结果完全错误.&lt;/p&gt;
&lt;h2 id="明文密码分组链接pcbc模式"&gt;明文密码分组链接(PCBC)模式
&lt;/h2&gt;&lt;p&gt;CBC和CFB模式下, 如下密文发生一个bit的错误, 会影响邻近的两个块的解密结果出错, 影响范围有限.
如果想要错误的影响范围更大, 就可以用PCBC模式.&lt;/p&gt;
&lt;p&gt;PCBC模式加密步骤如下:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;明文分组为P1, P2, P3&amp;hellip;&lt;/li&gt;
&lt;li&gt;生成一个128bit(等于一个分组的大小)的随机数作为iv&lt;/li&gt;
&lt;li&gt;iv 与 P1 异或, 得到 M1&lt;/li&gt;
&lt;li&gt;使用密钥加密M1, 得到密文C1&lt;/li&gt;
&lt;li&gt;C1 和 P1 和 P2 异或, 得到 M2&lt;/li&gt;
&lt;li&gt;使用密钥加密M2, 得到密文C2&lt;/li&gt;
&lt;li&gt;重复5和6的步骤, 直到所有明文使用完毕&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;PCBC模式与CBC模式区别在于步骤5, 对第二组明文加密前, 不只第一组的密文参与异或, 第一组的明文也参与异或,
这种做法导致密文中某个一bit的错误会引起后续所有分组的解密结果都出错, 使得错误变得非常明显.&lt;/p&gt;
&lt;h2 id="计数器ctr模式"&gt;计数器(CTR)模式
&lt;/h2&gt;&lt;p&gt;上述的OFB和CFB模式都可以把分组密码作为序列密码使用, 但是它们都有存在的问题是, 在加密序列的生成过程中,
每一个分组都依赖上一个分组的计算结果, 也就是下一个分组必须等待上一个分组计算完成后才可以开始计算,
这样就没法并行计算, 没法充分现代多核CPU的计算能力. CTR模式就是可以一种可以并行计算的工作模式.&lt;/p&gt;
&lt;p&gt;CTR模式加密步骤如下:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;明文分组为P1, P2, P3&amp;hellip;&lt;/li&gt;
&lt;li&gt;生成一个128bit(等于一个分组的大小)的随机数作为iv, 设置计数器Counter=0&lt;/li&gt;
&lt;li&gt;使用密钥加密iv, 得到加密序列 E1&lt;/li&gt;
&lt;li&gt;使用 E1 与 P1 异或, 生成密文 P1&lt;/li&gt;
&lt;li&gt;Count自增1&lt;/li&gt;
&lt;li&gt;使用密钥加密(iv + Counter), 得到加密序列 E2&lt;/li&gt;
&lt;li&gt;使用 E2 与 P2 异或, 生成密文 P2&lt;/li&gt;
&lt;li&gt;重复步骤5,6,7, 直至所有明文使用完毕&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;由CTR的加密步骤可以看出, 只要知道iv和分组的序号, 就可以独立计算出该分组的加密序列,
而不依赖其他分组的加密计算结果. 因此多核的CPU可以同时进行多个分组的加解密计算, 提高效率.
这个特性对于磁盘上的随机存取文件也很友好, 只要计算出分组序号就可以对加密文件中间的某一段做单独解密,
而不需要从头开始把整个文件解密才能读取中间的一段.&lt;/p&gt;</description></item><item><title>【Erlang】lists:all/2 和 lists:any/2 对于空列表运算结果是啥?</title><link>https://blog.cndenis.com/Erlang/2015/01/all_for_empty_list_is_true.html</link><pubDate>Mon, 12 Jan 2015 00:00:00 +0000</pubDate><guid>https://blog.cndenis.com/Erlang/2015/01/all_for_empty_list_is_true.html</guid><description>&lt;p&gt;先说结果, 无论F是什么, 结果都是这样:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nn"&gt;lists&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nn"&gt;lists&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;换成其它语言也一样.&lt;/p&gt;
&lt;h3 id="listsallf---true"&gt;lists:all(F, []) = true
&lt;/h3&gt;&lt;p&gt;从逻辑上, 假如 A 和 B 是两个列表, 那么:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;all(F, A ++ B) = all(F, A) andalso all(F, B)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;显然, 如果一个大列表全部都是true, 把大列表分割成两个子列表后,
每个子列表中所有元素也都是true.&lt;/p&gt;
&lt;p&gt;Erlang中, A = A ++ [], 所以&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;all(F, A ++ []) = all(F, A) andalso all(F, [])
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;只有 all(F, []) = true 才能保证上式恒成立.&lt;/p&gt;
&lt;h3 id="listsanyf---false"&gt;lists:any(F, []) = false
&lt;/h3&gt;&lt;p&gt;类似的,&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;any(F, A ++ B) = any(F, A) orelse all(F, B)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此,&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;any(F, A ++ []) = any(F, A) orelse all(F, [])
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;只有当 all(F, []) = false 才可以保证上式恒成立.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;参考:&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="http://stackoverflow.com/questions/11979683/why-python-built-in-all-function-returns-true-for-empty-iterables" target="_blank" rel="noopener"
 &gt;http://stackoverflow.com/questions/11979683/why-python-built-in-all-function-returns-true-for-empty-iterables&lt;/a&gt;&lt;/p&gt;</description></item><item><title>【Erlang】Erlang虚拟机的内部时钟</title><link>https://blog.cndenis.com/Erlang/2014/09/internal_time_of_erlang.html</link><pubDate>Fri, 19 Sep 2014 00:00:00 +0000</pubDate><guid>https://blog.cndenis.com/Erlang/2014/09/internal_time_of_erlang.html</guid><description>&lt;p&gt;Erlang虚拟机可视为一个小型操作系统, 有自己的一套时钟系统, 与系统时间并不是完全一致的.&lt;/p&gt;
&lt;p&gt;Erlang虚拟机时钟使用的是 &lt;code&gt;erlang:now()&lt;/code&gt; 获取, 系统时间使用 &lt;code&gt;os:timestamp()&lt;/code&gt; 获取.
格式是一样的三元组: {百万秒, 秒, 微秒}.&lt;/p&gt;
&lt;h3 id="erlang内部时钟的特点"&gt;Erlang内部时钟的特点
&lt;/h3&gt;&lt;p&gt;为什么Erlang需要实现自己的虚拟机时钟呢? 因为系统时钟有时是不可靠的,
可能会因为联网自动对时或是管理员调时钟而发生突变或往回走,
Erlang虚拟机时钟就是为了避免这些问题而设计的, 它有以下几个特点:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;单向: 永远不会往回走&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;时间间隔接近于真实: 如果在两个时间读取虚拟机时钟, 读数为T1和T2,
那么T1-T2的值接近于两个时间点的真实时间间隔.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;自动修正: 如果Erlang发现虚拟机内部时钟与系统时钟读数不一致,
它会自动缓慢地修正内部时钟, 使内部时钟与系统时钟一致.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;第二点是说: 如果两次读取系统时钟, 发现时间相差1小时,
不一定是真实时间过了一小时, 可能是时钟被拨快了1小时, 实际上只过了几秒
但Erlang虚拟机时钟则可以保证, 读数相差1小时, 那么实际时间过了&lt;strong&gt;大约&lt;/strong&gt;一小时,
误差不超过1%.&lt;/p&gt;
&lt;p&gt;第三点的实现方法是, Erlang发现内部时间和系统时间差距&amp;quot;较大&amp;quot;的话,
会调节内部时钟走时速度来适应外部时钟. 比方说外部时钟突然快了1分钟,
Erlang会用100分钟来&amp;quot;追赶&amp;quot;外部时钟, 这段时间内Erlang内部时钟走时会快1%.&lt;/p&gt;
&lt;p&gt;Erlang的这套时钟修正机制虽然不是完美的, 但可以避免出现时间跳跃问题,
防止定时器过早或过晚触发.&lt;/p&gt;
&lt;h3 id="erlang内部时钟的应用"&gt;Erlang内部时钟的应用
&lt;/h3&gt;&lt;p&gt;Erlang内部时钟在以下这个几地方使用:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;erlang:now()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;receive...after&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;timer&lt;/code&gt;模块&lt;/li&gt;
&lt;li&gt;&lt;code&gt;erlang:start_timer/3&lt;/code&gt; 和 &lt;code&gt;erlang:send_after/3&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这就是说, 如果你用&lt;code&gt;send_after&lt;/code&gt;设置1小时后给某进程发消息,
想调系统时间让消息快点到是不可能的, 老老实实等1小时吧.&lt;/p&gt;
&lt;h3 id="erlangnow-的特点"&gt;erlang:now() 的特点
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;单向&lt;/li&gt;
&lt;li&gt;间隔真实&lt;/li&gt;
&lt;li&gt;自动修正&lt;/li&gt;
&lt;li&gt;唯一&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;前三点由Erlang的内部时钟机制保证, 不必多说. 最后一点是指, 即使在多进程下,
每次调用&lt;code&gt;erlang:now()&lt;/code&gt;都会获得不同的值.
因此&lt;code&gt;erlang:now()&lt;/code&gt;的返回值也可以拿来当唯一ID用, 不用担心重复.&lt;/p&gt;
&lt;p&gt;不过这个机制也会造成在高频率(每秒大于1百万次)调用时, &lt;code&gt;erlang:now()&lt;/code&gt;的返回值有偏差.
因为它的返回值精度为1微秒, 1微秒调用2次的话, 也要值这个微秒数加2, 显得走快了.&lt;/p&gt;
&lt;p&gt;当系统时间走时正常, 而且调用频率不高时, &lt;code&gt;erlang:now()&lt;/code&gt;显示的时间和系统时间是一致的.&lt;/p&gt;
&lt;h3 id="关闭内部时钟自动修正"&gt;关闭内部时钟自动修正
&lt;/h3&gt;&lt;p&gt;可以在启动erl的时候, 使用+c参数, 关闭内部时钟的自动修正. 这是一般用不上的功能.&lt;/p&gt;
&lt;h3 id="erlangnow-vs-ostimestamp"&gt;erlang:now() vs os:timestamp()
&lt;/h3&gt;&lt;p&gt;os:timestamp()返回的是系统时钟, 调系统时间的时候就会立即改变.
这对于进行时间相关的逻辑的测试时是很有用的.&lt;/p&gt;
&lt;p&gt;erlang:now()在单进程下稍快于os:timestamp(), 但多进程竞争调用会变慢,
可以参考&lt;a class="link" href="http://stackoverflow.com/questions/17399544/erlangnow-0-is-faster-than-ostimestamp-0" target="_blank" rel="noopener"
 &gt;我在stackoverflow上的提问&lt;/a&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;参考: &lt;a class="link" href="http://www.erlang.org/doc/apps/erts/erts.pdf" target="_blank" rel="noopener"
 &gt;Erlang Run-Time System Application (ERTS)&lt;/a&gt; 第1.2节&lt;/p&gt;</description></item><item><title>【Erl代码片段】start_timer/3 发送的消息中的TimerRef的用途</title><link>https://blog.cndenis.com/Erlang/2014/06/usage_of_ref_in_start_timer.html</link><pubDate>Fri, 20 Jun 2014 00:00:00 +0000</pubDate><guid>https://blog.cndenis.com/Erlang/2014/06/usage_of_ref_in_start_timer.html</guid><description>&lt;p&gt;Erlang中有两个很相似的延迟发送消息的函数, &lt;code&gt;send_after/3&lt;/code&gt; 和 &lt;code&gt;start_timer/3&lt;/code&gt;,
区别仅在于前者返回&lt;code&gt;Msg&lt;/code&gt;, 后者返回&lt;code&gt;{timeout, TimerRef, Msg}&lt;/code&gt;.
后者的这个 &lt;code&gt;TimerRef&lt;/code&gt; 有什么用呢?&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="http://www.cnblogs.com/me-sa/archive/2012/03/16/erlang-timer.html" target="_blank" rel="noopener"
 &gt;坚强2002的博客&lt;/a&gt;给出了例子:&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;来自代码erl5.8.2\lib\stdlib-1.17.2\src\gen_fsm.erl&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;%% Returns Ref, sends event {timeout,Ref,Msg} after Time
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;%% to the (then) current state.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;start_timer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nn"&gt;erlang&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nb"&gt;start_timer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;&amp;#39;$gen_timer&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Msg&lt;/span&gt;&lt;span class="p"&gt;}).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;%% Returns Ref, sends Event after Time to the (then) current state.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;send_event_after&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nn"&gt;erlang&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nb"&gt;start_timer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;&amp;#39;$gen_event&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;}).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;%% Returns the remaing time for the timer if Ref referred to
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;%% an active timer/send_event_after, false otherwise.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cancel_timer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Ref&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nn"&gt;erlang&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nb"&gt;cancel_timer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Ref&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;false&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;receive&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Ref&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;_}&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;after&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;RemainingTime&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;RemainingTime&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;代码十分清楚, 在取消定时器后, 可以利用这个&lt;code&gt;Ref&lt;/code&gt;把消息队列中未处理的消息也删掉.&lt;/p&gt;
&lt;p&gt;类似的用法在&lt;code&gt;demonitor/1&lt;/code&gt;也可以看到. 取消掉一个monitor, 可以使用类似的方法,
把消息列队中的未处理的&lt;code&gt;'DOWN'&lt;/code&gt;消息删掉:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;demonitor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;MonitorRef&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;receive&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{_,&lt;/span&gt; &lt;span class="nv"&gt;MonitorRef&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;_,&lt;/span&gt; &lt;span class="p"&gt;_,&lt;/span&gt; &lt;span class="p"&gt;_}&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;after&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;但是这样的代码不用自己写, Erlang自带的 &lt;code&gt;demonitor(MonitorRef, [flush])&lt;/code&gt;
就等价于上面的代码.&lt;/p&gt;
&lt;p&gt;为什么&lt;code&gt;demonitor&lt;/code&gt;提供了&lt;code&gt;flush&lt;/code&gt;参数, 而&lt;code&gt;cancel_timer&lt;/code&gt;没有呢?
因为 &lt;code&gt;monitor/2&lt;/code&gt; 产生的消息只能发给调用它进程,
而 &lt;code&gt;start_timer&lt;/code&gt; 产生的消息可以发给任意进程.
由于Erlang只允许读取本进程的消息队列, 不能干涉别的进程,
所以 &lt;code&gt;cancel_timer&lt;/code&gt; 就不提供 &lt;code&gt;flush&lt;/code&gt; 参数, 避免误解.&lt;/p&gt;
&lt;p&gt;不过, 类似的 &lt;code&gt;unlink/1&lt;/code&gt; 却也没有相应的 &lt;code&gt;flush&lt;/code&gt; 参数可以用, 要自己刷消息队列:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;unlink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;receive&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;&amp;#39;EXIT&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;_}&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;after&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;呵呵.&lt;/p&gt;</description></item><item><title>【Erl代码片段】简易的并行版lists:map/2</title><link>https://blog.cndenis.com/Erlang/2014/06/parallel_list_map.html</link><pubDate>Mon, 16 Jun 2014 00:00:00 +0000</pubDate><guid>https://blog.cndenis.com/Erlang/2014/06/parallel_list_map.html</guid><description>&lt;p&gt;Joe在书上示范了一个并行化的&lt;code&gt;lists:map&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;pmap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;L&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;S&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c"&gt;%% make_ref() returns a unique reference
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c"&gt;%% we&amp;#39;ll match on this later
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;Ref&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;erlang&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;make_ref&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;Pids&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fun&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;I&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fun&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;do_f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Ref&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;I&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;L&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c"&gt;%% gather the results
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;gather&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Pids&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Ref&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;do_f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Parent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Ref&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;I&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;Parent&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nv"&gt;Ref&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="nv"&gt;F&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;I&lt;/span&gt;&lt;span class="p"&gt;))}.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;gather&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nv"&gt;Pid&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="nv"&gt;T&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nv"&gt;Ref&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;receive&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;Pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Ref&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Ret&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Ret&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="n"&gt;gather&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Ref&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;gather&lt;/span&gt;&lt;span class="p"&gt;([],&lt;/span&gt; &lt;span class="p"&gt;_)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[].&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其实里面的Ref是没什么必要的, Pid本身就是不重复的,
可以用列表解析改简短一点:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;pmap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;L&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;Parent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;receive&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;Pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;Result&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="nv"&gt;Pid&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fun&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;Parent&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="nv"&gt;F&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;X&lt;/span&gt;&lt;span class="p"&gt;))}&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="nv"&gt;X&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nv"&gt;L&lt;/span&gt;&lt;span class="p"&gt;]].&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果不在乎返回值的次序, 可以用霸爷的版本: &lt;a class="link" href="http://blog.yufeng.info/archives/401" target="_blank" rel="noopener"
 &gt;http://blog.yufeng.info/archives/401&lt;/a&gt;,
不过他没有在&lt;code&gt;F(X)&lt;/code&gt;前加&lt;code&gt;catch&lt;/code&gt;, 下面的代码中加上了.
他在论坛中解释说不加 &lt;code&gt;catch&lt;/code&gt; 是为了&amp;quot;fail fast&amp;quot;&lt;a class="link" href="http://www.iteye.com/topic/365175" target="_blank" rel="noopener"
 &gt;(链接)&lt;/a&gt;,
不过这并不完全成立, 因为&lt;code&gt;F(X)&lt;/code&gt;是在新建的进程中执行的, 而且没有link,
出错只会使调用者无限等待, 并不见得特别好.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;upmap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;L&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;Parent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;Ref&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;make_ref&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;receive&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;Ref&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;Result&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="p"&gt;_&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fun&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;Parent&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;Ref&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="nv"&gt;F&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;X&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="nv"&gt;X&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nv"&gt;L&lt;/span&gt;&lt;span class="p"&gt;]].&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Tsung里有一个限制产生进程数的版本:
&lt;a class="link" href="https://github.com/processone/tsung/blob/master/src/tsung/ts_utils.erl#L874" target="_blank" rel="noopener"
 &gt;https://github.com/processone/tsung/blob/master/src/tsung/ts_utils.erl#L874&lt;/a&gt;
如下:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;pmap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;L&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;NProcs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;pmap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;L&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;NProcs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;pmap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;L&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;NProcs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="nb"&gt;length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;L&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;NProcs&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;Head&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Tail&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;lists&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;NProcs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;L&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;Parent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nn"&gt;lists&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;foldl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fun&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;X&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Acc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fun&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;Parent&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nv"&gt;F&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;X&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nv"&gt;Acc&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nv"&gt;Acc&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Head&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;NewRes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;wait_result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;NProcs&lt;/span&gt;&lt;span class="p"&gt;,[]),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;pmap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;Tail&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;NProcs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Res&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="nv"&gt;NewRes&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;pmap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;L&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;_&lt;/span&gt;&lt;span class="nv"&gt;NProcs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Acc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;Acc&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="n"&gt;pmap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;L&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;wait_result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{_&lt;/span&gt;&lt;span class="nv"&gt;Ids&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;RealRes&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;lists&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;unzip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;lists&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;keysort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Res&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;RealRes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;wait_result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Nprocs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;receive&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{_&lt;/span&gt;&lt;span class="nv"&gt;Pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;NewRes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;Res&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="nv"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;wait_result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Nprocs&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;NewRes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这代码看起来并不怎么好, 子进程发送的 &lt;code&gt;{self(), F(X), Acc}&lt;/code&gt;
中&lt;code&gt;self()&lt;/code&gt;是没有用的, 底下的 &lt;code&gt;wait_result/2&lt;/code&gt; 也没有对它进行匹配,
合理来说这地方应该是一个 &lt;code&gt;Ref&lt;/code&gt; 才对.
而且代码中先是 &lt;code&gt;Res ++ [{Id, Result}]&lt;/code&gt;, 然后又做 &lt;code&gt;keysort&lt;/code&gt;, 并不太必要.&lt;/p&gt;
&lt;p&gt;其实用现成的 &lt;code&gt;pmap/2&lt;/code&gt; 去实现就可以了.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;pmap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;L&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;NProcs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;pmap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;L&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;NProcs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;pmap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;L&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;NProcs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="nb"&gt;length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;L&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;NProcs&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;Head&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Tail&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;lists&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;NProcs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;L&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;pmap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Tail&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;NProcs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;pmap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Head&lt;/span&gt;&lt;span class="p"&gt;)|&lt;/span&gt;&lt;span class="nv"&gt;Res&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;pmap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;L&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;_&lt;/span&gt;&lt;span class="nv"&gt;NProcs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;Res1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;pmap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;L&lt;/span&gt;&lt;span class="p"&gt;)|&lt;/span&gt;&lt;span class="nv"&gt;Res&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nn"&gt;lists&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;lists&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;reverse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Res1&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;由于创建进程和消息往返都有开销, 选择性消息接收会有遍历消息队列的开销,
只有当F是一个耗时的操作, 这些并行化的map才会比较划算.&lt;/p&gt;</description></item><item><title>【Erlang】ETS的并发性能调节选项</title><link>https://blog.cndenis.com/Erlang/2014/06/ets_read_write_concurrency.html</link><pubDate>Sun, 08 Jun 2014 00:00:00 +0000</pubDate><guid>https://blog.cndenis.com/Erlang/2014/06/ets_read_write_concurrency.html</guid><description>&lt;p&gt;ETS在创建表时, 有 &lt;code&gt;write_concurrency&lt;/code&gt; 和 &lt;code&gt;read_concurrency&lt;/code&gt; 这两个选项,
可以用以优化ETS的并发性能.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;write_concurrency&lt;/code&gt; 默认设置是 &lt;code&gt;false&lt;/code&gt;, 当表进行写操作时,
整个表会被锁起来, 直到写完为止. 把这个值设置为 &lt;code&gt;true&lt;/code&gt;, 可以优化并发写性能,
表中的不同项可以同时进行读写, 代价是会消耗一些内存, 并且会降低并发读的性能.
但是对于 &lt;code&gt;order_set&lt;/code&gt; 类型的表, 目前的Erlang版本下是不受这个选项影响的.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;read_concurrency&lt;/code&gt; 默认设置也是 &lt;code&gt;false&lt;/code&gt;, 当设置为 &lt;code&gt;true&lt;/code&gt;,
并且Erlang运行在多核机器上且开启SMP支持时, 并发读的性能会提升.
代价是读写切换变得更慢.&lt;/p&gt;
&lt;p&gt;这两个选项是不会对操作的原子性和独立性有影响的,
也就是说这两项设置&lt;strong&gt;只改变性能, 不影响逻辑&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;显然, &lt;code&gt;write_concurrency&lt;/code&gt; 适用于读少写多的表,
&lt;code&gt;read_concurrency&lt;/code&gt; 适用于读多写少的表, 以及读写交替少的表
(即读一大堆数据后再写一大堆, 读取操作较少被写入操作打断).&lt;/p&gt;
&lt;p&gt;这两个选项是可以同时开启的, 但额外的内存消耗会更大.&lt;/p&gt;
&lt;p&gt;测试一下, 分别对默认, 开启&lt;code&gt;read_concurrency&lt;/code&gt;, 开启&lt;code&gt;write_concurrency&lt;/code&gt; 这三种设置,
测试 &lt;code&gt;insert&lt;/code&gt;, &lt;code&gt;lookup&lt;/code&gt;, &lt;code&gt;update_counter&lt;/code&gt; 三种操作&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;bench for default ets
ets:insert/2
Single Process: 5664151 call per sec, 8388608 times in 1481 ms
 1000 Process: 2448296 call per sec, 4096000 times in 1673 ms
ets:lookup/2
Single Process: 6096372 call per sec, 8388608 times in 1376 ms
 1000 Process: 9481481 call per sec, 16384000 times in 1728 ms
ets:update_counter/3
Single Process: 5821379 call per sec, 8388608 times in 1441 ms
 1000 Process: 105872 call per sec, 128000 times in 1209 ms

bench for read_concurrency ets
ets:insert/2
Single Process: 5418997 call per sec, 8388608 times in 1548 ms
 1000 Process: 2493000 call per sec, 4096000 times in 1643 ms
ets:lookup/2
Single Process: 4981358 call per sec, 8388608 times in 1684 ms
 1000 Process: 10944555 call per sec, 16384000 times in 1497 ms
ets:update_counter/3
Single Process: 5769331 call per sec, 8388608 times in 1454 ms
 1000 Process: 1935727 call per sec, 2048000 times in 1058 ms

bench for write_concurrency ets
ets:insert/2
Single Process: 4371343 call per sec, 8388608 times in 1919 ms
 1000 Process: 2617252 call per sec, 4096000 times in 1565 ms
ets:lookup/2
Single Process: 4507580 call per sec, 8388608 times in 1861 ms
 1000 Process: 8062992 call per sec, 8192000 times in 1016 ms
ets:update_counter/3
Single Process: 4412734 call per sec, 8388608 times in 1901 ms
 1000 Process: 1889298 call per sec, 2048000 times in 1084 ms
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以看出, 开启并发性能优化的选项, 对于多进程的&lt;code&gt;update_counter&lt;/code&gt;的性能有很大帮助.&lt;/p&gt;</description></item><item><title>【Erlang】gen_server terminate的坑</title><link>https://blog.cndenis.com/Erlang/2014/06/pitfall_on_gen_server_terminate.html</link><pubDate>Sat, 07 Jun 2014 00:00:00 +0000</pubDate><guid>https://blog.cndenis.com/Erlang/2014/06/pitfall_on_gen_server_terminate.html</guid><description>&lt;p&gt;gen_server进程结束时, 会调用&lt;code&gt;terminate&lt;/code&gt;函数, 但这并不是在任何情况下都成立的.&lt;/p&gt;
&lt;p&gt;当gen_server进程主动关闭时, 也就是在回调函数 &lt;code&gt;handle_xxx&lt;/code&gt; 中返回 &lt;code&gt;{stop...}&lt;/code&gt;
的时候, &lt;code&gt;terminate&lt;/code&gt; 是必然被调用的.&lt;/p&gt;
&lt;p&gt;当gen_server进程处于监控树中, 被其监控进程关闭时, 情况就不一样了.
只有在这个进程设置了捕获退出信号, 即 &lt;code&gt;process_flag(trap_exit, true)&lt;/code&gt;,
并且其开启选项中设置了关闭超时时间, 而不是 &lt;code&gt;brutal_kill&lt;/code&gt;, &lt;code&gt;terminate&lt;/code&gt;才会被执行.&lt;/p&gt;
&lt;p&gt;换句话说, &lt;strong&gt;不捕获退出信号的gen_server被其监控进程关闭时, 会直接死掉,
不执行&lt;code&gt;terminate&lt;/code&gt;函数!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;看一下 &lt;code&gt;gen_server&lt;/code&gt; 的源代码关于消息处理的部分:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;decode_msg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Msg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Parent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;State&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Mod&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Hib&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nv"&gt;Msg&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;system&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;From&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Req&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nn"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;handle_system_msg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;From&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Parent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="nv"&gt;MODULE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;State&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Mod&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Time&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nv"&gt;Hib&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;&amp;#39;EXIT&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Parent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Reason&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;terminate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Reason&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Msg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Mod&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;State&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;_&lt;/span&gt;&lt;span class="nv"&gt;Msg&lt;/span&gt; &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="nv"&gt;Debug&lt;/span&gt; &lt;span class="o"&gt;=:=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;handle_msg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Msg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Parent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;State&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Mod&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;_&lt;/span&gt;&lt;span class="nv"&gt;Msg&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;Debug1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;handle_debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="n"&gt;print_event&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Msg&lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;handle_msg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Msg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Parent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;State&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Mod&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Debug1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;可以看出, 当它的父进程执行 &lt;code&gt;erlang:exit(Pid, Reason) &lt;/code&gt;时,
也就是给它发送 &lt;code&gt;{'EXIT', Parent, Reason}&lt;/code&gt;,
gen_server会调用 &lt;code&gt;terminate&lt;/code&gt; 并结束自己.
gen_server源代码中并没有设置 &lt;code&gt;trap_exit&lt;/code&gt;, 也就是默认是不捕获退出信号的,
如果用户不自己设置, 进程一旦接收到 &lt;code&gt;{'EXIT', Parent, Reason}&lt;/code&gt; 就会立即退出,
没有机会运行 &lt;code&gt;terminate&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;从这段代码也可以看出, 设置 &lt;code&gt;trap_exit&lt;/code&gt; 后, 用户并不需要而且没办法在 &lt;code&gt;handle_info&lt;/code&gt;
里处理来自监控树的父进程的退出信号, gen_server在这个消息在到达 &lt;code&gt;handle_info&lt;/code&gt;
之前就已经处理了, 直接调用了 &lt;code&gt;terminate&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;因此, 要确保监控树中的gen_server在进程结束时执行 &lt;code&gt;terminate&lt;/code&gt;,
需要设置 &lt;code&gt;process_flag(trap_exit, true)&lt;/code&gt;,
并且要在启动参数中, 设置足够长的结束等待时间.&lt;/p&gt;
&lt;p&gt;参考:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="http://mazenharake.wordpress.com/2010/10/31/9-erlang-pitfalls-you-should-know-about/" target="_blank" rel="noopener"
 &gt;9 Erlang pitfalls you should know about&lt;/a&gt;, 其中第7条讲的就是这个问题, 有试验代码.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="http://www.qingliangcn.com/2010/08/erlang-otp%E4%B9%8Bterminate-%E6%B7%B1%E5%85%A5%E5%88%86%E6%9E%90/" target="_blank" rel="noopener"
 &gt;Erlang OTP之terminate 深入分析&lt;/a&gt;, 庆亮写的分析, 也有试验代码.
其中对于 &lt;code&gt;simple_one_for_one&lt;/code&gt; 的描述不尽正确, 在目前的R16B中,
&lt;code&gt;simple_one_for_one&lt;/code&gt; 的子进程信息是存在 &lt;code&gt;#state.dynamics&lt;/code&gt; 中的,
只要处理时间足够, 关闭监控树是会正常关闭所有子进程的.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>OTP监控树笔记</title><link>https://blog.cndenis.com/Erlang/2014/06/note_of_otp_supervior_tree.html</link><pubDate>Thu, 05 Jun 2014 00:00:00 +0000</pubDate><guid>https://blog.cndenis.com/Erlang/2014/06/note_of_otp_supervior_tree.html</guid><description>&lt;p&gt;这是Learn You Some Erlang中的&lt;a class="link" href="http://learnyousomeerlang.com/building-applications-with-otp" target="_blank" rel="noopener"
 &gt;Building an Applications with Otp&lt;/a&gt;的笔记.&lt;/p&gt;
&lt;p&gt;在文中, OTP被戏称为Onion Theory Platform, 监控树像洋葱一样, 一层又一层.&lt;/p&gt;
&lt;p&gt;OTP的哲学是工人-监工, 工作进程做错事就让它死掉, 监督进程再开启新的工作进程来干活.
这样做有个让人觉得很麻烦的问题: 工作进程死掉了, 它的状态怎么办? 文中进行了讨论.
状态可以分成三类:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;静态的状态. 这从配置文件读回来就可以, 没什么问题.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;动态但可重新获取的状态. 就是那些可以利用初始状态计算而来的东西, 重新算就行了.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;动态且不可重新获取的状态. 比如说用户的输入, 外部事件等等.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果工作进程只有前两类状态, 用监工的方法很容易的处理, 死了重启, 恢复状态就可以了.&lt;/p&gt;
&lt;p&gt;第三类的状态需要放到不允许出错的地方(error kernel), 其实就是用try&amp;hellip;catch包起来.&lt;/p&gt;
&lt;p&gt;作者示范了一个进程池的设计.&lt;/p&gt;
&lt;p&gt;所谓进程池, 就是可以容纳一定数量的进程同时运行, 当同时运行的进程数达到限制时,
把工作放入队列进行排队, 等待有空位时再开始新的任务.&lt;/p&gt;
&lt;p&gt;做这么一个进程池, 需要有一个服务进程来计数同时运行的工作进程数,
以及保存准备等待运行的队列.&lt;/p&gt;
&lt;p&gt;那用这个服务进程来监控工作进程好不好呢? 可以, 但缺点是服务进程任务太重,
而且和现有的监督者进程功能重复.&lt;/p&gt;
&lt;p&gt;一个比较好的方案是, 用一个监督进程&lt;code&gt;worker_sup&lt;/code&gt;监视所有工作进程,
这个监督进程和进程池服务进程一起放到上一层的监督进程&lt;code&gt;ppool_sup&lt;/code&gt;下, 如图:&lt;/p&gt;
&lt;img src=http://learnyousomeerlang.com/static/img/ppool_sup.png&gt;
&lt;p&gt;如果让所有进程池都放在同一个&lt;code&gt;ppool_sup&lt;/code&gt;下, 当一个进程池频繁出错的话,
这个&lt;code&gt;ppool_sup&lt;/code&gt;会被关掉, 所有进程池都会被关掉, 这是很不好的事情.
所以要为每个进程池单独开一个监控进程. 变成这样:&lt;/p&gt;
&lt;img src=http://learnyousomeerlang.com/static/img/ppool_supersup.png&gt;
&lt;p&gt;底下的具体实现部分就不记了.&lt;/p&gt;
&lt;p&gt;实现这么看起来并不太复杂的功能, 从顶层到worker, 总共四层, 不愧是洋葱理论平台.&lt;/p&gt;</description></item><item><title>Apache启动时报443端口被占用的处理方法</title><link>https://blog.cndenis.com/Web/2014/06/cannot_bind_443_on_apache_startup.html</link><pubDate>Mon, 02 Jun 2014 00:00:00 +0000</pubDate><guid>https://blog.cndenis.com/Web/2014/06/cannot_bind_443_on_apache_startup.html</guid><description>&lt;p&gt;下午在自己机上装了Apache2.4, 启动时说443端口被占了:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(OS 10048)通常每个套接字地址(协议/网络地址/端口)只允许使用一次。 : AH00072: mak
e_sock: could not bind to address [::]:443
(OS 10048)通常每个套接字地址(协议/网络地址/端口)只允许使用一次。 : AH00072: mak
e_sock: could not bind to address 0.0.0.0:443
AH00451: no listening sockets available, shutting down
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;杀掉占用443的那个程序当然可以, 另一种方法是把443改成另外的不常用端口:
如&lt;a class="link" href="http://congjl2002.iteye.com/blog/1497640" target="_blank" rel="noopener"
 &gt;这篇文章&lt;/a&gt;介绍的,
还有一种方法是直接关闭Apache的SSL模块, 反正在我自己的机上用不着.&lt;/p&gt;
&lt;p&gt;打开&lt;code&gt;httpd.conf&lt;/code&gt;, 找到加载ssl_module的那一行, 加#号注释掉就好了:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# LoadModule ssl_module modules/mod_ssl.so
&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>【Erl代码片段】cowboy的一处大小写处理代码</title><link>https://blog.cndenis.com/Erlang/2014/05/cowboy_inline_lower_case.html</link><pubDate>Fri, 30 May 2014 00:00:00 +0000</pubDate><guid>https://blog.cndenis.com/Erlang/2014/05/cowboy_inline_lower_case.html</guid><description>&lt;p&gt;在cowboy的库cowlib中的&lt;a class="link" href="https://github.com/extend/cowlib/blob/master/include/cow_inline.hrl" target="_blank" rel="noopener"
 &gt;cow_inline.hrl&lt;/a&gt;文件看到一堆很长的宏:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="ni"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;INLINE_LOWERCASE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Acc&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$A&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;Acc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;$a&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$B&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;Acc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;$b&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$C&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;Acc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;$c&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$D&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;Acc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;$d&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$E&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;Acc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;$e&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$F&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;Acc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;$f&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$G&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;Acc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;$g&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$H&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;Acc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;$h&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$I&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;Acc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;$i&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$J&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;Acc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;$j&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$K&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;Acc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;$k&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$L&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;Acc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;$l&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$M&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;Acc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;$m&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$N&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;Acc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;$n&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$O&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;Acc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;$o&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$P&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;Acc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;$p&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$Q&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;Acc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;$q&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$R&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;Acc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;$r&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$S&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;Acc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;$s&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$T&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;Acc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;$t&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$U&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;Acc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;$u&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$V&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;Acc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;$v&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$W&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;Acc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;$w&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$X&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;Acc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;$x&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$Y&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;Acc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;$y&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$Z&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;Acc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;$z&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;C&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;Acc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;C&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;底下还有2参数,3参数&amp;hellip;10参数的版本.&lt;/p&gt;
&lt;p&gt;找到一个调用的地方看看: &lt;a class="link" href="https://github.com/extend/cowboy/blob/master/src/cowboy_protocol.erl" target="_blank" rel="noopener"
 &gt;cowboy_protocol.erl&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;parse_hd_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;C&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;bits&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;M&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;V&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;H&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;SoFar&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nv"&gt;C&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$:&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;parse_hd_before_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;M&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;V&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;H&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;SoFar&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$\s&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;parse_hd_name_ws&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;M&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;V&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;H&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;SoFar&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$\t&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;parse_hd_name_ws&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;M&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;V&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;H&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;SoFar&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="nv"&gt;INLINE_LOWERCASE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parse_hd_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;M&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;V&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;H&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;SoFar&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;还是看不明白, 用&lt;code&gt;c(cowboy_protocol, ['P'])&lt;/code&gt;查看展开的宏, 上面的代码变成了:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;parse_hd_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;C&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;bits&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;M&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;V&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;H&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;SoFar&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nv"&gt;C&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$:&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;parse_hd_before_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;M&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;V&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;H&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;SoFar&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$ &lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;parse_hd_name_ws&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;M&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;V&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;H&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;SoFar&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$\t&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;parse_hd_name_ws&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;M&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;V&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;H&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;SoFar&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$A&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;parse_hd_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;M&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;V&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;H&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;SoFar&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sc"&gt;$a&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$B&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;parse_hd_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;M&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;V&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;H&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;SoFar&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sc"&gt;$b&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$C&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;parse_hd_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;M&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;V&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;H&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;SoFar&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sc"&gt;$c&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$D&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;parse_hd_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;M&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;V&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;H&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;SoFar&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sc"&gt;$d&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$E&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;parse_hd_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;M&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;V&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;H&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;SoFar&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sc"&gt;$e&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$F&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;parse_hd_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;M&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;V&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;H&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;SoFar&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sc"&gt;$f&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$G&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;parse_hd_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;M&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;V&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;H&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;SoFar&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sc"&gt;$g&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$H&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;parse_hd_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;M&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;V&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;H&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;SoFar&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sc"&gt;$h&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$I&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;parse_hd_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;M&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;V&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;H&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;SoFar&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sc"&gt;$i&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$J&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;parse_hd_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;M&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;V&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;H&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;SoFar&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sc"&gt;$j&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$K&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;parse_hd_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;M&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;V&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;H&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;SoFar&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sc"&gt;$k&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$L&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;parse_hd_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;M&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;V&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;H&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;SoFar&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sc"&gt;$l&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$M&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;parse_hd_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;M&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;V&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;H&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;SoFar&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sc"&gt;$m&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$N&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;parse_hd_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;M&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;V&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;H&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;SoFar&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sc"&gt;$n&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$O&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;parse_hd_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;M&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;V&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;H&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;SoFar&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sc"&gt;$o&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$P&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;parse_hd_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;M&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;V&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;H&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;SoFar&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sc"&gt;$p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$Q&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;parse_hd_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;M&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;V&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;H&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;SoFar&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sc"&gt;$q&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$R&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;parse_hd_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;M&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;V&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;H&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;SoFar&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sc"&gt;$r&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$S&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;parse_hd_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;M&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;V&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;H&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;SoFar&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sc"&gt;$s&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$T&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;parse_hd_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;M&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;V&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;H&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;SoFar&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sc"&gt;$t&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$U&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;parse_hd_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;M&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;V&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;H&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;SoFar&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sc"&gt;$u&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$V&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;parse_hd_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;M&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;V&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;H&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;SoFar&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sc"&gt;$v&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$W&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;parse_hd_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;M&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;V&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;H&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;SoFar&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sc"&gt;$w&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$X&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;parse_hd_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;M&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;V&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;H&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;SoFar&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sc"&gt;$x&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$Y&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;parse_hd_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;M&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;V&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;H&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;SoFar&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sc"&gt;$y&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sc"&gt;$Z&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;parse_hd_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;M&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;V&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;H&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;SoFar&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sc"&gt;$z&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;C&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;parse_hd_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;M&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;V&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;H&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;SoFar&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;C&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;嗯, 这样就明白多了, 就是进行程序的逻辑处理同时, 把大写字母转换成小写.&lt;/p&gt;
&lt;p&gt;测试一下这种写法的效率, 把一个大写的二进制串转成小写.
Erlang没有原生的对二进制串做大小写转换的方法, 所以要先转列表, 转小写后再转回来.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;%% 先转列表
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;lower_by_list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;B&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;list_to_binary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;string&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;to_lower&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;binary_to_list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;B&lt;/span&gt;&lt;span class="p"&gt;))).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;%% inline的方法
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;lower_by_inline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;B&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;lower_by_inline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;B&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;lower_by_inline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;C&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;R&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;bits&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Acc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nv"&gt;C&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="nv"&gt;INLINE_LOWERCASE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lower_by_inline&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;R&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Acc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;lower_by_inline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Acc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;Acc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;对于1K字节的大写二进制串, 运行结果如下:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;len: 1024
bench:lower_by_list/1
Single Process: 29925 call per sec, 32768 times in 1095 ms

bench:lower_by_inline/1
Single Process: 25090 call per sec, 32768 times in 1306 ms
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果单是做大小写转换, 这么做并不比先转列表再转回来快, 不过是可以省一点内存.&lt;/p&gt;
&lt;p&gt;想起Erlang文档里的一句话: Do not guess about performance
&lt;a class="link" href="http://www.erlang.org/documentation/doc-5.2/doc/efficiency_guide/profiling.html" target="_blank" rel="noopener"
 &gt;出自这里&lt;/a&gt;. 这里用了相当复杂的方法完成了一个简单的工作,
或许是针对项目需求极度优化的结果, 如果不顾场合照搬, 那就是给自己添麻烦了.&lt;/p&gt;</description></item><item><title>【Erl代码片段】更快的proplists:get_value/3</title><link>https://blog.cndenis.com/Erlang/2014/05/faster_proplists_get_value.html</link><pubDate>Fri, 30 May 2014 00:00:00 +0000</pubDate><guid>https://blog.cndenis.com/Erlang/2014/05/faster_proplists_get_value.html</guid><description>&lt;p&gt;在cowboy的&lt;a class="link" href="https://github.com/extend/cowboy/blob/master/src/cowboy_protocol.erl" target="_blank" rel="noopener"
 &gt;cowboy_protocol.erl&lt;/a&gt;
文件中看到如这样一下函数:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;%% Faster alternative to proplists:get_value/3.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;get_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Opts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nn"&gt;lists&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;keyfind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Opts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{_,&lt;/span&gt; &lt;span class="nv"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;_&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;Default&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;做了一下测试, 考虑到proplist一般都不长, 用一个10个元素的列表进行测试,
结果这个函数比 &lt;code&gt;proplists:get_value/3&lt;/code&gt; 快5倍, 对于更长的列表差别更大.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;bench:get_value/3
Single Process: 13035909 call per sec, 16777216 times in 1287 ms

proplists:get_value/3
Single Process: 2273335 call per sec, 4194304 times in 1845 ms
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;速度差别原因主要是, &lt;code&gt;keyfind&lt;/code&gt; 是BIF, 用C实现的,
而 &lt;code&gt;proplists:get_value/3&lt;/code&gt; 是erlang实现的,
另外 &lt;code&gt;proplists:get_value/3&lt;/code&gt; 把 atom 当作 {atom, true} 处理,
逻辑比 &lt;code&gt;keyfind&lt;/code&gt; 复杂一些&lt;/p&gt;
&lt;p&gt;这里另外一个测试和讨论:
&lt;a class="link" href="http://www.ostinelli.net/erlang-listskeyfind-or-proplistsget_value/" target="_blank" rel="noopener"
 &gt;http://www.ostinelli.net/erlang-listskeyfind-or-proplistsget_value/&lt;/a&gt;,&lt;/p&gt;</description></item><item><title>Erlang数据项的size</title><link>https://blog.cndenis.com/Erlang/2014/05/Erlang%E4%B8%AD%E7%9A%84%E5%90%84%E7%A7%8Dsize.html</link><pubDate>Wed, 07 May 2014 00:00:00 +0000</pubDate><guid>https://blog.cndenis.com/Erlang/2014/05/Erlang%E4%B8%AD%E7%9A%84%E5%90%84%E7%A7%8Dsize.html</guid><description>&lt;p&gt;Erlang中数据项(Erlang Term)的所占据的空间大小可以用各种size来获取.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;其中对于所有数据项都通用的有: &lt;code&gt;erlang:external_size/1&lt;/code&gt;, &lt;code&gt;erts_debug:size/1&lt;/code&gt;, &lt;code&gt;erts_debug:flat_size/1&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;适用于二进制串有: &lt;code&gt;erlang:size/1&lt;/code&gt;, &lt;code&gt;erlang:byte_size/1&lt;/code&gt;, &lt;code&gt;erlang:bit_size/1&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;适用于元组的有: &lt;code&gt;erlang:size/1&lt;/code&gt;, &lt;code&gt;erlang:tuple_size/1&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="erlangexternal_size1"&gt;&lt;code&gt;erlang:external_size/1&lt;/code&gt;
&lt;/h3&gt;&lt;p&gt;&lt;a class="link" href="http://erlang.org/doc/man/erlang.html#external_size-1" target="_blank" rel="noopener"
 &gt;erlang:external_size/1&lt;/a&gt; 用来获取erlang数据项的外部格式(&lt;a class="link" href="http://erlang.org/doc/apps/erts/erl_ext_dist.html" target="_blank" rel="noopener"
 &gt;External Term Format&lt;/a&gt;)&lt;em&gt;最大&lt;/em&gt;大小. 所谓外部格式, 就是用&lt;code&gt;term_to_binary/1&lt;/code&gt;
打包形成的格式, 如果要把数据项从一台节点发到另一个节点, 或是持久化装到数据库中,
就需要打包成外部格式. 因此, 这个函数计算的传输erlang数据项的IO开销, 可以用来计算网络带宽或磁盘空间的占用量. 文档上说如下关系始终成立:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt; Size1 = byte_size(term_to_binary(Term)),
&amp;gt; Size2 = erlang:external_size(Term),
&amp;gt; true = Size1 =&amp;lt; Size2.
true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也就是说用&lt;code&gt;external_size/1&lt;/code&gt;函数算出来的空间需求可能会大于实际用&lt;code&gt;term_to_binary/1&lt;/code&gt;
打包后的体积, 但这对于进行空间预算是没有问题的.&lt;/p&gt;
&lt;p&gt;这个函数还有带多一个参数的版本&lt;a class="link" href="http://erlang.org/doc/man/erlang.html#external_size-2" target="_blank" rel="noopener"
 &gt;erlang:external_size/2&lt;/a&gt;, 可以指打包的格式的版本, 目前版本之间只是对浮点数的处理有点不一样.&lt;/p&gt;
&lt;h3 id="erts_debugflat_size1-和-erts_debugsize1"&gt;&lt;code&gt;erts_debug:flat_size/1&lt;/code&gt; 和 &lt;code&gt;erts_debug:size/1&lt;/code&gt;
&lt;/h3&gt;&lt;p&gt;&lt;code&gt;erts_debug:size/1&lt;/code&gt; 和 &lt;code&gt;erts_debug:flat_size/1&lt;/code&gt; 都是不在正式文档中的函数,
可以用来计算erlang数据项在内存中所需要空间. 各种数据项的空间占用可以在这里找到:
&lt;a class="link" href="http://www.erlang.org/doc/efficiency_guide/advanced.html#id68912" target="_blank" rel="noopener"
 &gt;http://www.erlang.org/doc/efficiency_guide/advanced.html#id68912&lt;/a&gt;. 这两个函数区别在于,
在具有共享内存的数据结构中, &lt;code&gt;erts_debug:size/1&lt;/code&gt;只计算一次共享的数据大小,
而&lt;code&gt;erts_debug:flat_size/1&lt;/code&gt;则会重复计算.&lt;/p&gt;
&lt;p&gt;这是erlang源代码中的例子:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;%% size(Term)
%% Returns the size of Term in actual heap words. Shared subterms are
%% counted once. Example: If A = [a,b], B =[A,A] then size(B) returns 8,
%% while flat_size(B) returns 12.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;文档中有另外一个例子: &lt;a class="link" href="http://www.erlang.org/doc/efficiency_guide/processes.html" target="_blank" rel="noopener"
 &gt;http://www.erlang.org/doc/efficiency_guide/processes.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;总的来说, &lt;code&gt;erts_debug:size/1&lt;/code&gt;是erlang数据项在内存中所占用的空间大小,
&lt;code&gt;erts_debug:flat_size/1&lt;/code&gt;是同一节点内, 跨进程移动数据项(包括ETS操作)所需要拷贝的数据大小.&lt;/p&gt;
&lt;h3 id="erlangtuple_size1"&gt;&lt;code&gt;erlang:tuple_size/1&lt;/code&gt;
&lt;/h3&gt;&lt;p&gt;作为自动导入的BIF, 一般不用写模块名&lt;code&gt;erlang:&lt;/code&gt;. 这个函数功能很简单,
计算元组所包含的元素个数, 对于元组T来说, &lt;code&gt;size(T)&lt;/code&gt; 就等于&lt;code&gt;tuple_size(T)&lt;/code&gt;,
后者指明了数据类型, 运行时微微快一点.&lt;/p&gt;
&lt;h3 id="erlangbyte_size1-和-erlangbit_size1"&gt;&lt;code&gt;erlang:byte_size/1&lt;/code&gt; 和 &lt;code&gt;erlang:bit_size/1&lt;/code&gt;
&lt;/h3&gt;&lt;p&gt;这两个也是自动导入, 一般不用写模块名. 它们是用来计算二进制串(binary)或是比特串(bitstring)所占的空间的. 对于二进制串B来说, &lt;code&gt;size(B)&lt;/code&gt; 等于 &lt;code&gt;byte_size(B)&lt;/code&gt;.&lt;/p&gt;</description></item><item><title>使用jqPlot绘制统计图-1</title><link>https://blog.cndenis.com/Web/2013/11/%E4%BD%BF%E7%94%A8jqPlot%E7%BB%98%E5%88%B6%E7%BB%9F%E8%AE%A1%E5%9B%BE-1.html</link><pubDate>Sun, 03 Nov 2013 00:00:00 +0000</pubDate><guid>https://blog.cndenis.com/Web/2013/11/%E4%BD%BF%E7%94%A8jqPlot%E7%BB%98%E5%88%B6%E7%BB%9F%E8%AE%A1%E5%9B%BE-1.html</guid><description>&lt;p&gt;要在网页上显示统计图, 可以在服务器生成图片后发给浏览器, 也可以把数据发给浏览器,
用JavaScript画. &lt;a class="link" href="http://www.jqplot.com/" target="_blank" rel="noopener"
 &gt;jqPlot&lt;/a&gt;是后者的一种, 它是jQuery的一个插件,
是完全运行于客户端的绘图包. 下面简介一下它的使用.&lt;/p&gt;
&lt;h3 id="引用库文件"&gt;引用库文件
&lt;/h3&gt;&lt;p&gt;jqPlot 是 jQuery 插件, 需要在网页上引用 jQuery 和 jqPlot 包中的以下的几个文件.&lt;/p&gt;
&lt;p&gt;要注意这几个只是最基本的, 要做出各种图形效果的话, 需要另外再引用其他的一些文件,
后面会分别介绍.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;&amp;lt;!--[if lt IE 9]&amp;gt;&amp;lt;script language=&amp;#34;javascript&amp;#34; type=&amp;#34;text/javascript&amp;#34; src=&amp;#34;excanvas.js&amp;#34;&amp;gt;&amp;lt;/script&amp;gt;&amp;lt;![endif]--&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt; &lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;javascript&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;text/javascript&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;jquery.min.js&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt; &lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;javascript&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;text/javascript&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;jquery.jqplot.min.js&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;link&lt;/span&gt; &lt;span class="na"&gt;rel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;stylesheet&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;text/css&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;jquery.jqplot.css&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="放置图片的容器"&gt;放置图片的容器
&lt;/h3&gt;&lt;p&gt;把以下容器放在需要显示图片的地方, 注意必需要预先设定好大小.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;chartdiv&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;height:250px;width:500px; &amp;#34;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="画图"&gt;画图
&lt;/h3&gt;&lt;p&gt;以下是做一个最简单的图的例子:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;jqplot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;chartdiv&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[[[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;5.12&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;13.1&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;33.6&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;85.9&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;219.9&lt;/span&gt;&lt;span class="p"&gt;]]]);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;画出来的图是这样的:&lt;/p&gt;
&lt;div id="chartdiv" style="height:250px;width:500px; "&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;$.jqplot&lt;/code&gt; 是用来作图的, 它的形式是&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;$.jqplot(容器ID, 数据, 参数)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;要注意其中的容器ID并不是 jQuery 的选择器, 不带&lt;code&gt;#&lt;/code&gt;号.&lt;/p&gt;
&lt;p&gt;数据是以一个二元组为一个点, 如&lt;code&gt;[1, 2]&lt;/code&gt;, 以若干个点的列表作为一个系列
(也就是一条曲线), 数据可以包含多个系列, 于是你就会看到是三层的列表(&lt;code&gt;[[[&lt;/code&gt;)&lt;/p&gt;
&lt;p&gt;参数是一个&lt;a class="link" href="http://www.json.org/json-zh.html" target="_blank" rel="noopener"
 &gt;JSON对像&lt;/a&gt;,
jqPlot的所有应用技巧就都装在里面了.&lt;/p&gt;
&lt;p&gt;下面是一个具有多条曲线, 并且设定标题的图:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;jqplot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;chartdiv2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;这是三条曲线&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div id="chartdiv2" style="height:250px;width:500px; "&gt;&lt;/div&gt;
&lt;!--[if lt IE 9]&gt;&lt;script language="javascript" type="text/javascript" src="http://www.jqplot.com/deploy/dist/excanvas.js"&gt;&lt;/script&gt;&lt;![endif]--&gt;
&lt;script language="javascript" type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"&gt;&lt;/script&gt;
&lt;script language="javascript" type="text/javascript" src="//cdn.jsdelivr.net/jqplot/1.0.8/jquery.jqplot.js"&gt;&lt;/script&gt;
&lt;link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/jqplot/1.0.8/jquery.jqplot.css" /&gt;
&lt;script&gt;
$(
function(){
 $.jqplot('chartdiv', [[[1, 2],[3,5.12],[5,13.1],[7,33.6],[9,85.9],[11,219.9]]]);
 $.jqplot('chartdiv2',[
 [[1, 2],[2,4],[3,7],[4,15],[5,20],[6,16]],
 [[1, 3],[2,6],[3,9],[4,12],[5,5],[6,2]],
 [[1, 2],[2,4],[3,2],[4,7],[5,3],[6,5]]
 ], {title:'这是三条曲线'});
})
&lt;/script&gt;</description></item><item><title>在Jekyll的博客中实现语法高亮</title><link>https://blog.cndenis.com/Web/2013/11/%E5%9C%A8Jekyll%E7%9A%84%E5%8D%9A%E5%AE%A2%E4%B8%AD%E5%AE%9E%E7%8E%B0%E8%AF%AD%E6%B3%95%E9%AB%98%E4%BA%AE.html</link><pubDate>Sun, 03 Nov 2013 00:00:00 +0000</pubDate><guid>https://blog.cndenis.com/Web/2013/11/%E5%9C%A8Jekyll%E7%9A%84%E5%8D%9A%E5%AE%A2%E4%B8%AD%E5%AE%9E%E7%8E%B0%E8%AF%AD%E6%B3%95%E9%AB%98%E4%BA%AE.html</guid><description>&lt;p&gt;在Jekyll的博客中实现语法高亮方法如下:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;在配置文件 &lt;code&gt;_config.yml&lt;/code&gt; 启用 pygments, 并使用redcarpet做为渲染引擎.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;pygments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;markdown&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;redcarpet&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol start="2"&gt;
&lt;li&gt;使用以下格式把代码括起来&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;
 ```python
 print("hello world")
 ```
&lt;/pre&gt;
&lt;ol start="3"&gt;
&lt;li&gt;在页面上添加语法高亮的CSS文件, 像这样:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;link&lt;/span&gt; &lt;span class="na"&gt;rel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;stylesheet&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;/css/pygments.css&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;说明:&lt;/p&gt;
&lt;p&gt;使用 redcarpet 是为了支持所谓的 &lt;a class="link" href="https://help.github.com/articles/github-flavored-markdown" target="_blank" rel="noopener"
 &gt;Github风格的Markdown语法&lt;/a&gt;,
也就是像上面的那样三撇号加语言类型的方式进行代码引用,
其他几个渲染引擎要用&lt;a class="link" href="http://jekyllrb.com/docs/templates/#code_snippet_highlighting" target="_blank" rel="noopener"
 &gt;这种比较别扭的方式&lt;/a&gt;来把代码括起来, 我觉得这么写不好看.&lt;/p&gt;
&lt;p&gt;语法高亮的定义文件可以在 &lt;a class="link" href="https://github.com/richleland/pygments-css/tree/master" target="_blank" rel="noopener"
 &gt;这里&lt;/a&gt;下载, 对应的效果可以在 &lt;a class="link" href="http://pygments.org/demo/" target="_blank" rel="noopener"
 &gt;pygments的官网的Demo&lt;/a&gt;里试看.&lt;/p&gt;
&lt;p&gt;一直在纠结我的 Blog 中的代码为啥没有语法高亮,
看着&lt;a class="link" href="http://jekyllrb.com/" target="_blank" rel="noopener"
 &gt;Jekyll官网&lt;/a&gt;中漂亮的代码就更纠结了, 今天终于解决了,
刚把十几篇文章的代码都加上语言类型, 呼&amp;hellip;&lt;/p&gt;
&lt;p&gt;本文参考了:
&lt;a class="link" href="http://alexpeattie.com/blog/github-style-syntax-highlighting-with-pygments/" target="_blank" rel="noopener"
 &gt;GITHUB-STYLE SYNTAX HIGHLIGHTING WITH PYGMENTS&lt;/a&gt;&lt;/p&gt;</description></item><item><title>在Markdown里放JavaScript代码</title><link>https://blog.cndenis.com/Web/2013/11/%E5%9C%A8Markdown%E9%87%8C%E6%94%BEJavaScript%E4%BB%A3%E7%A0%81.html</link><pubDate>Sun, 03 Nov 2013 00:00:00 +0000</pubDate><guid>https://blog.cndenis.com/Web/2013/11/%E5%9C%A8Markdown%E9%87%8C%E6%94%BEJavaScript%E4%BB%A3%E7%A0%81.html</guid><description>&lt;p&gt;MarkDown里是可以直接放HTML标签的, 也可以放&lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt;, 但是要注意的是,
&lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; 前要空一行, 这样才不会被当成文本.&lt;/p&gt;
&lt;p&gt;也有人说要在&lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt;后面空一行, 我这里试了一下, 似乎不空也行.&lt;/p&gt;
&lt;p&gt;参考: &lt;a class="link" href="http://stackoverflow.com/questions/2754391/embed-javascript-in-markdown" target="_blank" rel="noopener"
 &gt;Embed javascript in markdown&lt;/a&gt;&lt;/p&gt;</description></item><item><title>MySQL中 REPLACE 与 INSERT ON DUPLICATE KEY UPDATE 的区别</title><link>https://blog.cndenis.com/Web/2013/10/MySQL%E4%B8%ADREPLACE%E4%B8%8EINSERT_ON_DUPLICATE_KEY_UPDATE%E7%9A%84%E5%8C%BA%E5%88%AB.html</link><pubDate>Wed, 30 Oct 2013 00:00:00 +0000</pubDate><guid>https://blog.cndenis.com/Web/2013/10/MySQL%E4%B8%ADREPLACE%E4%B8%8EINSERT_ON_DUPLICATE_KEY_UPDATE%E7%9A%84%E5%8C%BA%E5%88%AB.html</guid><description>&lt;p&gt;MySQL中, 要一步实现 &amp;ldquo;如果没有则插入, 如果存在则替换&amp;rdquo; 这样的操作, 有两种方式,
&lt;code&gt;REPLACE&lt;/code&gt; 和 &lt;code&gt;INSERT ... ON DUPLICATE KEY UPDATE&lt;/code&gt;. 这两种方法是有区别的.&lt;/p&gt;
&lt;p&gt;它们之间的共同点是, 要求表中有 &lt;code&gt;UNIQUE&lt;/code&gt; 或 &lt;code&gt;PRIMARY KEY&lt;/code&gt; 的列,
不然没法判断是否需要替换, 这两都会变成和普通 &lt;code&gt;INSERT&lt;/code&gt; 一样了.&lt;/p&gt;
&lt;p&gt;不同之处在于, 如果存在重复的主键值, &lt;code&gt;REPLACE&lt;/code&gt; 执行的是&lt;strong&gt;先删除, 后插入&lt;/strong&gt;.
这样做一个后果是会导致索引碎片化, 降低效率. 更重要的是,
这条命令是无法进行部分更新的, 命令中没有赋值的列, 都会被设为&lt;strong&gt;默认值&lt;/strong&gt;!&lt;/p&gt;
&lt;p&gt;&lt;code&gt;REPLACE&lt;/code&gt; 的语法示例如下:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;REPLACE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INTO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ratings&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;quote_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;INSERT ... ON DUPLICATE KEY UPDATE&lt;/code&gt; 进行的操作是, 如果存在重复的主键值,
则执行&lt;code&gt;UPDATE&lt;/code&gt;子句的操作, 这是可以保留未赋值列的原值的. 如果没有重复主键,
它就是普通的 &lt;code&gt;INSERT&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;示例如下:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INTO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ratings&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;quote_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DUPLICATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;本文参考了:
&lt;a class="link" href="http://thomashunter.name/blog/mysql-replace-vs-insert-on-duplicate-key-update/" target="_blank" rel="noopener"
 &gt;MySQL REPLACE vs INSERT ON DUPLICATE KEY UPDATE&lt;/a&gt;&lt;/p&gt;</description></item><item><title>雷人的PHP的运算符优先级</title><link>https://blog.cndenis.com/Web/2013/10/PHP%E7%9A%84%E8%BF%90%E7%AE%97%E7%AC%A6%E4%BC%98%E5%85%88%E7%BA%A7.html</link><pubDate>Wed, 30 Oct 2013 00:00:00 +0000</pubDate><guid>https://blog.cndenis.com/Web/2013/10/PHP%E7%9A%84%E8%BF%90%E7%AE%97%E7%AC%A6%E4%BC%98%E5%85%88%E7%BA%A7.html</guid><description>&lt;p&gt;PHP中的运算符优先级, 比较运算符高于位运算符, 赋值运算符高于部分逻辑运算符,
真是坑啊.&lt;/p&gt;
&lt;p&gt;比较运算符高于位运算符, 所以&lt;/p&gt;
&lt;p&gt;&lt;code&gt;$A == $B &amp;amp; $C&lt;/code&gt; 等价于 &lt;code&gt;($A == $B) &amp;amp; $C&lt;/code&gt; 而 &lt;strong&gt;不是先做&lt;code&gt;&amp;amp;&lt;/code&gt;再进行比较&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;赋值运算 &lt;code&gt;and&lt;/code&gt; &lt;code&gt;or&lt;/code&gt; &lt;code&gt;xor&lt;/code&gt; 高于逻辑运算, 但却低于 &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; 和 &lt;code&gt;||&lt;/code&gt;, 所以&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="nx"&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt; &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;var_dump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 输出是 bool(true)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt; &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;var_dump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 输出是 bool(false)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上面那行居然是 &lt;strong&gt;先把 &lt;code&gt;true&lt;/code&gt; 赋给 &lt;code&gt;$a&lt;/code&gt;&lt;/strong&gt;, 然后再与后面的&lt;code&gt;false&lt;/code&gt;做逻辑与.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; 和 &lt;code&gt;and&lt;/code&gt; 居然还不等价, 雷死人了.&lt;/p&gt;
&lt;p&gt;以后还是要习惯多加括号了.&lt;/p&gt;
&lt;p&gt;完整的优先级列表可以参考
&lt;a class="link" href="http://php.net/manual/zh/language.operators.precedence.php" target="_blank" rel="noopener"
 &gt;官方手册&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;刚发现还有另外的坑, 这个优先级是有例外的:
&lt;a class="link" href="http://www.laruence.com/2010/07/26/1668.html" target="_blank" rel="noopener"
 &gt;PHP运算符优先级的一个例外&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Erlang中IPv4地址与整数的转换</title><link>https://blog.cndenis.com/Erlang/2013/10/Erlang%E4%B8%ADIPv4%E5%9C%B0%E5%9D%80%E4%B8%8E%E6%95%B4%E6%95%B0%E7%9A%84%E8%BD%AC%E6%8D%A2.html</link><pubDate>Tue, 29 Oct 2013 00:00:00 +0000</pubDate><guid>https://blog.cndenis.com/Erlang/2013/10/Erlang%E4%B8%ADIPv4%E5%9C%B0%E5%9D%80%E4%B8%8E%E6%95%B4%E6%95%B0%E7%9A%84%E8%BD%AC%E6%8D%A2.html</guid><description>&lt;p&gt;IPv4地址通常表示为 A.B.C.D, 其中A-D都是0-255之间的整数, 总长为32位, 因此,
可以使用单一个32位无符号整数表示一个IP地址.&lt;/p&gt;
&lt;p&gt;Erlang 中可以使用以下方式进行转换:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;ip_to_int&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;B&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;C&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;D&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;B&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;C&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;D&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;int_to_ip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;B&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;C&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;D&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;B&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;C&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;D&lt;/span&gt;&lt;span class="p"&gt;}.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上面两个函数没考虑溢出的问题, 溢出的部分会被截断, 比如说 A 输入 257 会被视为 1.&lt;/p&gt;
&lt;p&gt;用二进制语法进行这种转换实在是优美, 比乘啊除啊好看多了.&lt;/p&gt;</description></item><item><title>Erlang的大小比较</title><link>https://blog.cndenis.com/Erlang/2013/10/Erlang%E7%9A%84%E5%A4%A7%E5%B0%8F%E6%AF%94%E8%BE%83.html</link><pubDate>Thu, 24 Oct 2013 00:00:00 +0000</pubDate><guid>https://blog.cndenis.com/Erlang/2013/10/Erlang%E7%9A%84%E5%A4%A7%E5%B0%8F%E6%AF%94%E8%BE%83.html</guid><description>&lt;p&gt;Erlang 里, 不只数字可以比较大小, 基本上所有变量都可以比较大小.&lt;/p&gt;
&lt;p&gt;大小关系是:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;数字 &amp;lt; 原子 &amp;lt; reference &amp;lt; 函数 &amp;lt; 端口 &amp;lt; pid &amp;lt; 元组 &amp;lt; 列表 &amp;lt; 二进制
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也就是说, 数字总是比原子小, 原子总是比列表小&amp;hellip;&lt;/p&gt;
&lt;p&gt;也就是说, 即使 &lt;code&gt;Val &amp;gt; 5&lt;/code&gt; 为 &lt;code&gt;true&lt;/code&gt;, 也不能保证 &lt;code&gt;Val&lt;/code&gt; 是个数字.&lt;/p&gt;
&lt;p&gt;而且, 同一种非数字类型也有大小, 比如说&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="c"&gt;%% 假
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s"&gt;&amp;#34;b&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;aa&amp;#34;&lt;/span&gt; &lt;span class="c"&gt;%% 真
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;想不明白这样比较大小有啥意义, 真是个坑啊.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;update: 2014年6月8日&lt;/p&gt;
&lt;p&gt;所有数据项都可以比较, 在进行&lt;code&gt;lists:sort/2&lt;/code&gt;的时候就会很方便.&lt;/p&gt;
&lt;p&gt;而且, 要保证 &lt;code&gt;Val&lt;/code&gt; 是个数字, 更合理的应该是 &lt;code&gt;is_number(Val)&lt;/code&gt;, 而不是判断它的大小.&lt;/p&gt;</description></item><item><title>去除disqus的广告</title><link>https://blog.cndenis.com/Web/2013/09/%E5%8E%BB%E9%99%A4disqus%E5%B9%BF%E5%91%8A.html</link><pubDate>Tue, 17 Sep 2013 00:00:00 +0000</pubDate><guid>https://blog.cndenis.com/Web/2013/09/%E5%8E%BB%E9%99%A4disqus%E5%B9%BF%E5%91%8A.html</guid><description>&lt;p&gt;&lt;a class="link" href="http://jekyllbootstrap.com/" target="_blank" rel="noopener"
 &gt;Jekyll-Bootstrap&lt;/a&gt; 自带了&lt;a class="link" href="https://disqus.com/" target="_blank" rel="noopener"
 &gt;Disqus&lt;/a&gt;支持,
但Disqus默认自带广告, 看起来有点不爽. Google了一下找到去除广告方法:&lt;/p&gt;
&lt;p&gt;首先是要注册Disqus账号, 在博客的配置文件&lt;code&gt;_config.yml&lt;/code&gt;中找到&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;comments &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;provider &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;disqus&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;disqus &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;short_name &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;YOUR_NAME&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在&lt;code&gt;short_name&lt;/code&gt;后填上自己的账号, 把原先博客中示例的评论框换成自己.&lt;/p&gt;
&lt;p&gt;然后上Disqus网站, 按下图修改即可&lt;/p&gt;
&lt;img src="http://farm8.staticflickr.com/7343/9784821822_e40b24656a_o.png" alt="去除disqus广告"&gt;
&lt;p&gt;参考:&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="http://www.scottallen.com/2013/03/how-to-remove-disqus-ads-from-your-wordpress-blog/" target="_blank" rel="noopener"
 &gt;How to Remove Disqus Ads From Your WordPress Blog&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Erlang的静态代码检查</title><link>https://blog.cndenis.com/Erlang/2013/08/Erlang%E7%9A%84%E9%9D%99%E6%80%81%E4%BB%A3%E7%A0%81%E6%A3%80%E6%9F%A5.html</link><pubDate>Thu, 01 Aug 2013 00:00:00 +0000</pubDate><guid>https://blog.cndenis.com/Erlang/2013/08/Erlang%E7%9A%84%E9%9D%99%E6%80%81%E4%BB%A3%E7%A0%81%E6%A3%80%E6%9F%A5.html</guid><description>&lt;p&gt;Dialyzer是Erlang的静态代码检查程序, 可以发现函数调用时的类型错误之类的问题,
以及被调用的函数不存在或未导出的问题. 最实用的是在上传代码到SVN后,
检查是否漏传模块. 因为漏传的话, 编译不会报错, 但运行时会出undef错误,
从SVN上检出一份全新的代码, 用Dialyzer查一下, 漏的马上可以发现.&lt;/p&gt;
&lt;p&gt;Dialyzer用法很简单, 只有三步: 建立PLT文件, 编译代码, 运行检查.&lt;/p&gt;
&lt;h2 id="建立plt文件"&gt;建立PLT文件
&lt;/h2&gt;&lt;p&gt;PLT文件是Dialyzer所用的代码规则的记录, 或者说是索引.
一般把代码所用到的几个常用的Erlang系统库加到PLT文件中就好了.&lt;/p&gt;
&lt;p&gt;开始使用Dialyzer之前请先确定Erlang已正确安装, dialyzer.exe在系统搜索路径中.&lt;/p&gt;
&lt;p&gt;写Dialyzer模块的人用的是Linux, 所以这东西对Windows不是特别友好,
它的PLT文件默认存放在HOME目录下, 而Windows一般是没有这个环境变量的,
所以Dialyzer一运行就报错. 因此首先要设置HOME变量, 指定为一个目录,
用以存放PLT文件.&lt;/p&gt;
&lt;p&gt;建立PLT文件的命令是&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; dialyzer --build_plt --apps erts kernel stdlib mnesia
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其实 &lt;code&gt;--build_plt&lt;/code&gt; 参数表示建立PLT文件,
&lt;code&gt;--app&lt;/code&gt; 后面写上代码中引用到的内置库即可.&lt;/p&gt;
&lt;p&gt;这个命令运行时间比较长, 可能达到十几分钟, 请去喝杯咖啡慢慢等.&lt;/p&gt;
&lt;p&gt;如果发现已经建立的PLT文件中漏了某些库, 可以使用 &lt;code&gt;--add_to_plt&lt;/code&gt; 添加.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; dialyzer --build_plt --apps eunit
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其实一不用加太多, 最常用的就上面几个, 检查代码时如果发现漏了, 再用
&lt;code&gt;--add_to_plt&lt;/code&gt; 加上即可.&lt;/p&gt;
&lt;h2 id="编译代码"&gt;编译代码
&lt;/h2&gt;&lt;p&gt;Dialyzer可以检查源代码erl文件, 也可以检查编译好的beam文件.
我推荐是检查beam文件, 速度比较快.&lt;/p&gt;
&lt;p&gt;用Dialyzer检查beam文件要求在编译beam文件时加上debug_info参数,
这样生成出来的beam才能用于dialyzer检查.&lt;/p&gt;
&lt;h2 id="运行检查"&gt;运行检查
&lt;/h2&gt;&lt;p&gt;对于编译好的beam文件, 只需要进入beam所在目录, 运行&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; dialyzer .
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;即可检查该目录下所有beam文件, 或是&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; dialyzer 文件名
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;即可检查某一文件.&lt;/p&gt;
&lt;p&gt;如果希望把结果写入一个文件中, 可以使用&lt;code&gt;-o&lt;/code&gt;参数, 如:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; dialyzer . -o Result.txt
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这样会把结果写入&lt;code&gt;Result.txt&lt;/code&gt;中.&lt;/p&gt;</description></item><item><title>Erlang中的长度</title><link>https://blog.cndenis.com/Erlang/2013/04/Erlang%E4%B8%AD%E7%9A%84%E9%95%BF%E5%BA%A6.html</link><pubDate>Sat, 27 Apr 2013 00:00:00 +0000</pubDate><guid>https://blog.cndenis.com/Erlang/2013/04/Erlang%E4%B8%AD%E7%9A%84%E9%95%BF%E5%BA%A6.html</guid><description>&lt;p&gt;值得吐槽的是居然连求长度这么基础的方法，Erlang都没有统一起来。
分为len和size两大对立阵营：&lt;/p&gt;
&lt;h3 id="len阵营"&gt;len阵营
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;列表（字符串是列表的一种）的长度用&lt;code&gt;length/1&lt;/code&gt;或&lt;code&gt;string:len/1&lt;/code&gt;。
别看后面那个打着string开头，对于不是字符串的列表也照用不误，
从源代码看其实就是前一个的马甲。&lt;/li&gt;
&lt;li&gt;queue模块是len阵营的，使用&lt;code&gt;queue:len/1&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="size阵营"&gt;size阵营
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;二进制串的长度用&lt;code&gt;size/1&lt;/code&gt;，或是用&lt;code&gt;byte_size/1&lt;/code&gt;和&lt;code&gt;bit_size/1&lt;/code&gt;也行，分别是
比特长度和位长度，1byte = 8bit。&lt;/li&gt;
&lt;li&gt;元组的长度也用&lt;code&gt;size/1&lt;/code&gt;，等于其元素的个数。元组的比特长度和位长度不可用。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dict&lt;/code&gt;，&lt;code&gt;sets&lt;/code&gt;，&lt;code&gt;orddict&lt;/code&gt;，&lt;code&gt;ordsets&lt;/code&gt;，&lt;code&gt;array&lt;/code&gt;, &lt;code&gt;gb_trees&lt;/code&gt;, &lt;code&gt;gb_sets&lt;/code&gt; 这几个模块也是size阵营的，使用其各自模块
下的size函数。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;iolist&lt;/code&gt; 有BIF &lt;code&gt;iolist_size/1&lt;/code&gt;可用.&lt;/li&gt;
&lt;li&gt;ets比较特别，使用&lt;code&gt;ets:info(Tab, size)&lt;/code&gt;来获取长度，Tab是表的id，或是已注册的表的名字。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;另外，特立独行的“原子”没有长度。&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="更新2013年9月13日"&gt;更新(2013年9月13日)
&lt;/h4&gt;&lt;p&gt;其实Erlang对这两个方法的区分也是道理的, len是O(n)时是复杂度的函数 (是不是觉得这是另一种蛋疼),
而size是O(1)的. 换句话说就是数据长度越大, 取len的时间越长, 但取size用的时间却不受长度影响.&lt;/p&gt;</description></item><item><title>Erlang中的原子、字符串和二进制串</title><link>https://blog.cndenis.com/Erlang/2013/04/Erlang%E4%B8%AD%E7%9A%84%E5%8E%9F%E5%AD%90%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%92%8C%E4%BA%8C%E8%BF%9B%E5%88%B6%E4%B8%B2.html</link><pubDate>Fri, 26 Apr 2013 00:00:00 +0000</pubDate><guid>https://blog.cndenis.com/Erlang/2013/04/Erlang%E4%B8%AD%E7%9A%84%E5%8E%9F%E5%AD%90%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%92%8C%E4%BA%8C%E8%BF%9B%E5%88%B6%E4%B8%B2.html</guid><description>&lt;p&gt;Erlang中的原子（Atom）, 字符串（String）和二进制串（Binary）是有点容易让人糊涂
的东西, 这里归纳一下它们之间的区别与联系。&lt;/p&gt;
&lt;h2 id="原子"&gt;原子
&lt;/h2&gt;&lt;p&gt;原子是由小写字母开头, 后接大小写字母及数字及下划线的, 比方说abc, cDE, ff89,
或是由单引号&amp;rsquo;&amp;lsquo;括起来的任意字符, 比方说&amp;rsquo;EXIT&amp;rsquo;, &amp;lsquo;!@#@!$sdaf&amp;rsquo;。
用过其他语言的话, 会觉得Erlang中没括起来的原子长得像变量, 括起来的
长得像字符串, 但其实都不是, 这点要特别注意。Erlang中的变量是以大写字母
开头的, 字符串是用双引号括起来的。&lt;/p&gt;
&lt;p&gt;原子在Erlang中应用非常广, 模块名、函数名、记录名都是原子, 所以如果你够蛋疼的话,
可以用&amp;rsquo;!#@$#y3fdsa1&amp;rsquo;（包括两边的单引号）当做函数名。&lt;/p&gt;
&lt;p&gt;原子顾名思义是“不可分割”的东西, 原子无论长短, 在内存中占用的空间都是一样的,
然而, 原子的名字也不是毫无意义的, 可以利用&lt;code&gt;atom_to_binary&lt;/code&gt;把原子名转成二进制串,
也可以用&lt;code&gt;atom_to_list&lt;/code&gt;把原子名转成字符串。
反过来也可以, 有&lt;code&gt;binary_to_atom&lt;/code&gt;和&lt;code&gt;list_to_atom&lt;/code&gt;可以用。&lt;/p&gt;
&lt;p&gt;Erlang中是没有原生的原子连接方法, 真想要相连的话, 先要转成二进制串或是字符串.&lt;/p&gt;
&lt;h2 id="字符串"&gt;字符串
&lt;/h2&gt;&lt;p&gt;Erlang中字符串是使用双引号括起来的一串字符, 例如&amp;quot;string&amp;quot;, &amp;ldquo;123&amp;quot;等等。
双引号其实只是一个简写形式, 其实并没有把“字符串”当作一种独立的数据类型,
而是用正整数的列表（List）作为字符串使用, 跟C里面的做法相似。以下三行是等价的：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s"&gt;&amp;#34;hello&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sc"&gt;$h&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;$e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;$l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;$l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;$o&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;104&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;101&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;108&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;108&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;111&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;因此字符串转换成原子及二进制串的的函数名为&lt;code&gt;list_to_atom&lt;/code&gt;和&lt;code&gt;list_to_binary&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;Erlang中的有专门处理字符串的模块, &lt;code&gt;string&lt;/code&gt;, 可以用以进行大小写变换、截断、
对齐、连接、分割、子字符串等等常用操作。由于字符串实质上是列表, 因此&lt;code&gt;lists&lt;/code&gt;
模块里的方法也全都适用于字符串。&lt;/p&gt;
&lt;p&gt;字符串是列表, 因此可以使用列表的连接运算符&lt;code&gt;++&lt;/code&gt;进行连接。二进制串是不可以用&lt;code&gt;++&lt;/code&gt;的。
虽然拿 &lt;code&gt;字符串++二进制串&lt;/code&gt; 在语法上是允许的, 但得到的结果是一个 &amp;ldquo;非正规列表&amp;rdquo;
（也有人翻译成 &amp;ldquo;非严格列表&amp;rdquo; ）, 是不推荐这么做的。&lt;/p&gt;
&lt;h2 id="二进制串"&gt;二进制串
&lt;/h2&gt;&lt;p&gt;二进制串是Erlang的一项特色, 使用在代码中使用&lt;code&gt;&amp;lt;&amp;lt; &amp;gt;&amp;gt;&lt;/code&gt;括起来（看起来有点像中文的
书名号, 其实是两个小于号和两个大于号）。括起来的内容可以用数字表示, 或是用对应
的字符串表示, 如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;97&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;98&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;99&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;abc&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这两者含义是相同的。但要注意的是, 和列表&lt;code&gt;[ ]&lt;/code&gt;或元组&lt;code&gt;{ }&lt;/code&gt;不一样的是,
双引号只是一种简记方式, 并不是说把一个字符串放到&lt;code&gt;&amp;lt;&amp;lt; &amp;gt;&amp;gt;&lt;/code&gt;里就会变成二进制串的,
比方说以下的写法都是不对的。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;97&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;98&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;99&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;A&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;abc&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;A&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;正确的做法是:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;A&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;abc&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;A1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;list_to_binary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;A1&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c"&gt;%% 或者
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;list_to_binary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;记住, &lt;strong&gt;在二进制串中使用函数的话, 必须要用括号括起来&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;&amp;lt; &amp;gt;&amp;gt;&lt;/code&gt;里可以接受数字和二进制串, 利用所谓的比特语法构造二进制串或进行模式匹配。
格式为 &lt;code&gt;变量:大小/类型&lt;/code&gt;, 例如:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;X&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;little&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;signed&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;integer&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nn"&gt;unit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt; &lt;span class="c"&gt;%% 把X存为有符号小端整数, 大小为 4*8 bit
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;integer&lt;/span&gt; &lt;span class="c"&gt;%% 把A存储为32位整数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;B&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt; &lt;span class="c"&gt;%% 要求B是长于或等于15字节的二进制串, 截取B的前15字节
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;变量:大小/类型&lt;/code&gt; 的格式中, 大小和类型是可以省略的, 因此可以有:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;变量:大小
变量/类型
变量
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;当进行省略时, 会使用默认值:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;缺省的类型是整数 ( &lt;a class="link" href="http://www.erlang.org/doc/programming_examples/bit_syntax.html" target="_blank" rel="noopener"
 &gt;手册&lt;/a&gt;
上的例子是有点问题的, &amp;laquo;3.14&amp;raquo;这样的写法在 Erlang 16B 版上是非法的).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;缺省的大小与类型有关:&lt;/p&gt;
&lt;p&gt;整数是8位, &lt;em&gt;溢出部分被截掉&lt;/em&gt;: 例如&lt;code&gt;&amp;lt;&amp;lt; 257 &amp;gt;&amp;gt;&lt;/code&gt;等价于&lt;code&gt;&amp;lt;&amp;lt; 257:8 &amp;gt;&amp;gt;&lt;/code&gt;, 值等于&lt;code&gt;&amp;lt;&amp;lt; 1 &amp;gt;&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;浮点数是64位&lt;/p&gt;
&lt;p&gt;二进制串是整个串的长度: 例如&lt;code&gt;&amp;lt;&amp;lt; A/binary &amp;gt;&amp;gt;&lt;/code&gt;会把整个A都存起来.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;对于整数, 缺省是无符号的.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;对于整数, 缺省是大端的(big-endian).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;可以使用 &lt;code&gt;-unit:长度&lt;/code&gt; 的方式来指定单位长度, 缺省的单位长度与类型有关.&lt;/p&gt;
&lt;p&gt;整数(integer)/浮点数(float)/字节串(bitstring) 的缺省长度是1.&lt;/p&gt;
&lt;p&gt;而binary类型缺省长度是8.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;二进制的连接直接在&lt;code&gt;&amp;lt;&amp;lt; &amp;gt;&amp;gt;&lt;/code&gt;中使用逗号放一起就可以了, 例如&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;B&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1234&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;String&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;中文也可以&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;引号的后面不能加/binary&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;但是二进制串中括另一个二进制串要指定格式&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其它的二进制语法, 例如二进制中的模式匹配/二进制解析, 等等, 就不在这里讲了.&lt;/p&gt;
&lt;p&gt;参考:&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="http://www.erlang.org/doc/programming_examples/bit_syntax.html" target="_blank" rel="noopener"
 &gt;官方手册&lt;/a&gt;&lt;/p&gt;</description></item><item><title>gen_server笔记</title><link>https://blog.cndenis.com/Erlang/2013/04/gen_server%E7%AC%94%E8%AE%B0.html</link><pubDate>Wed, 24 Apr 2013 00:00:00 +0000</pubDate><guid>https://blog.cndenis.com/Erlang/2013/04/gen_server%E7%AC%94%E8%AE%B0.html</guid><description>&lt;p&gt;gen_server是erlang的OTP框架中最常用的“行为模式”了吧，至少几本erlang教材都是首
先介绍这个。&lt;/p&gt;
&lt;strike&gt;
这东西用来做什么的呢？或者说，为什么要用这东西呢？由于我接触这东西不过几天，
理解尚非常粗浅，就我看来，用gen_server有以下几个好处：
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;面向对像，封装数据与方法&lt;/em&gt;。gen_server内部需要维护一个状态State，并提供各种函数
给别人调用，就类似于其他语言中的“类”一样，把数据和方法封装在一起，防止数据被非法
改动。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;简化调用，屏蔽通讯&lt;/em&gt;。erlang中如果要自己实现远程过程调用（RPC）的话，需要自己
定义消息格式，自己编写封装与解包的代码，还要处理各种异常问题，这些gen_server
都帮我们做好了，只需要像平常使用函数一样直接调就用行了，省时省力还不出错。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;热代码替换等高级功能&lt;/em&gt;。 热代码替换是erlang大力宣传的一项特色功能，不停机维护
在生产上是非常美妙的事。不过这是高级功能，初学暂时用不上，书上也没多讲。
&lt;/strike&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="gen_server模板"&gt;gen_server模板
&lt;/h2&gt;&lt;p&gt;gen_server是可以使用模板来写的，如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;behaviour&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gen_server&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c"&gt;%% API
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;export&lt;/span&gt;&lt;span class="p"&gt;([]).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c"&gt;%% gen_server callbacks
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;export&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handle_call&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handle_cast&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handle_info&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;terminate&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;code_change&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;SERVER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="nv"&gt;MODULE&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;start_link&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nn"&gt;gen_server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;start_link&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="nv"&gt;SERVER&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="nv"&gt;MODULE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="p"&gt;[]).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;([])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;State&lt;/span&gt;&lt;span class="p"&gt;}.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;handle_call&lt;/span&gt;&lt;span class="p"&gt;(_&lt;/span&gt;&lt;span class="nv"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;_&lt;/span&gt;&lt;span class="nv"&gt;From&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;State&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Reply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;State&lt;/span&gt;&lt;span class="p"&gt;}.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;handle_cast&lt;/span&gt;&lt;span class="p"&gt;(_&lt;/span&gt;&lt;span class="nv"&gt;Msg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;State&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;noreply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;State&lt;/span&gt;&lt;span class="p"&gt;}.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;handle_info&lt;/span&gt;&lt;span class="p"&gt;(_&lt;/span&gt;&lt;span class="nv"&gt;Info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;State&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;noreply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;State&lt;/span&gt;&lt;span class="p"&gt;}.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;terminate&lt;/span&gt;&lt;span class="p"&gt;(_&lt;/span&gt;&lt;span class="nv"&gt;Reason&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;_&lt;/span&gt;&lt;span class="nv"&gt;State&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;code_change&lt;/span&gt;&lt;span class="p"&gt;(_&lt;/span&gt;&lt;span class="nv"&gt;OldVsn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;State&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;_&lt;/span&gt;&lt;span class="nv"&gt;Extra&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;State&lt;/span&gt;&lt;span class="p"&gt;}.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;含义如下：&lt;/p&gt;
&lt;p&gt;-module 是模块名，就是文件名。&lt;/p&gt;
&lt;p&gt;-behaviour 是指定“行为模式”，在这里就是gen_server，作用在于用于检查这个模块是否
实现gen_server的所有接口。也就是 &lt;code&gt;init/1&lt;/code&gt;, &lt;code&gt;handle_call/3&lt;/code&gt;, &lt;code&gt;handle_cast/2&lt;/code&gt;,
&lt;code&gt;handle_info/2&lt;/code&gt;, &lt;code&gt;terminate/2&lt;/code&gt;, &lt;code&gt;code_change/3&lt;/code&gt;这六个函数。缺少的话编译器就会
报错。&lt;/p&gt;
&lt;p&gt;-export 有两个，第一个里面写的是API，也就是供别人调用的接口，第二个是gen_server
的接口，就是上面说的那六个。其实要写到同一个export里也可以，不过分开写比较清楚。&lt;/p&gt;
&lt;p&gt;接下来就是各API函数，一般来说就是封装、调用各用回调函数的包装函数。&lt;/p&gt;
&lt;p&gt;再往后就是六个回调函数的具体实现。回调函数是负责具体干活的。&lt;/p&gt;
&lt;p&gt;大概可以做这么个比喻吧，如果整个模块是个昆虫，API是就头，gen_server就是身子，而
回调函数是六条腿。你告诉头说要去哪里，腿就运动起来，整条虫子就跑起来了。身子是
把各条腿粘起来，否则单独的腿只能在原地抽筋，哪都去不了。&lt;/p&gt;
&lt;h2 id="启动服务器"&gt;启动服务器
&lt;/h2&gt;&lt;p&gt;用来启动服务器的有&lt;code&gt;start/3&lt;/code&gt;,&lt;code&gt;start/4&lt;/code&gt;,&lt;code&gt;start_link/3&lt;/code&gt;,&lt;code&gt;start_link/4&lt;/code&gt;这四个函数。
使用这些start函数之后，就会产生一个新的进程，也就是一个gen_server服务器。这些
start函数的正常情况下返回值是&lt;code&gt;{ok,Pid}&lt;/code&gt;，&lt;code&gt;Pid&lt;/code&gt;就是这个新进程的进程号。
带link与不带的区别在于是否跟父进程建立链接，换种说法是，新启动的进程死掉后，
会不会通知启动他的进程（父进程）。&lt;/p&gt;
&lt;p&gt;start函数可以四个参数&lt;code&gt;(ServerName, Module, Args, Options)&lt;/code&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;第一个参数&lt;code&gt;ServerName&lt;/code&gt;是服务名，
是可以省掉的。具有相同服务名的模块在一个节点中只能启动一次，重复启动会报错，为
&lt;code&gt;{error, {already_started, Pid}}&lt;/code&gt;。具有服务名的服务进程可以使用服务名来调用，
没有服务名的只能通过进程号pid来调用了。通常有名字的服务进程会使用模块名做为
服务名，即上面模板中定义的宏&lt;code&gt;-define(SERVER, ?MODULE)&lt;/code&gt;，然后在需要使用服务名的
地方填入&lt;code&gt;?SERVER&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;第二个参数&lt;code&gt;Module&lt;/code&gt;是模块名，一般而言API和回调函数是写在同一个文件里的，所以就用
&lt;code&gt;?MODULE&lt;/code&gt;，表示本模块的模块名。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;第三个参数&lt;code&gt;Args&lt;/code&gt;是回调函数&lt;code&gt;init/1&lt;/code&gt;的参数，会原封不动地传给&lt;code&gt;init/1&lt;/code&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;第四个参数&lt;code&gt;Options&lt;/code&gt;是一些选项，可以设置debug、超时等东西。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;start是对应的回调函数是&lt;code&gt;init/1&lt;/code&gt;，一般来说是进行服务器启动后的一些初始化的工作，
并生成初始的状态State，正常返回是{ok, State}。这个State是贯穿整个服务器，
并把所有六个回调函数联系起来的纽带。它的值最初由&lt;code&gt;init/1&lt;/code&gt;生成，
此后可以由三个handle函数修改，每次修改后又要放回返回值中，
供下一个被调用的handle函数使用。
如果&lt;code&gt;init/1&lt;/code&gt;返回&lt;code&gt;ignore&lt;/code&gt;或&lt;code&gt;{stop, Reason}&lt;/code&gt;，则会中止服务器的启动。&lt;/p&gt;
&lt;p&gt;有一点细节要注意的是，API函数和回调函数虽然习惯上是写在同一个文件中，但执行函数
的进程却通常是不一样的。在上面的模板中，&lt;code&gt;start_link/0&lt;/code&gt;中使用&lt;code&gt;self()&lt;/code&gt;的话，显示
的是调用者的进程号，而在&lt;code&gt;init/1&lt;/code&gt;中使用&lt;code&gt;self()&lt;/code&gt;的话，显示的是服务器的进程号。&lt;/p&gt;
&lt;h2 id="使用服务器"&gt;使用服务器
&lt;/h2&gt;&lt;p&gt;三个handle开头的回调函数对应着三种不同的使用服务器的方式。如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;gen_server:call ------------- handle_call/3
gen_server:cast ------------- handle_cast/2
用！向服务进程发消息------------- handle_info/2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;call是有返回值的调用；cast是无返回值的调用，即通知；而直接向服务器进程发的
消息则由handle_info处理。&lt;/p&gt;
&lt;h3 id="call"&gt;call
&lt;/h3&gt;&lt;p&gt;call是有返回值的调用，也是所谓的同步调用，进程会在调用后一直等待直到回调函数返回为止。
它的函数形式是 &lt;code&gt;gen_server:call(ServerRef, Request, Timeout) -&amp;gt; Reply&lt;/code&gt;，&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;第一个参数&lt;code&gt;ServerRef&lt;/code&gt;是被调用的服务器，如果是服务器名，或是服务器的pid。&lt;/li&gt;
&lt;li&gt;第二个参数&lt;code&gt;Request&lt;/code&gt;会直接传给回调函数&lt;code&gt;handle_call&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;最后一个参数&lt;code&gt;Timeout&lt;/code&gt;是超时，是可以省略的，默认值是5秒。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在多节点的情况下，还有机会使用到&lt;code&gt;multi_call&lt;/code&gt;，用来向各节点上的同具有相同注册名
的服务进程发起调用。（这个函数在文档上的表述有点让人难以理解，详见
&lt;a class="link" href="http://erlang.2086793.n4.nabble.com/Question-about-gen-server-multi-call-2-td2104905.html" target="_blank" rel="noopener"
 &gt;这里&lt;/a&gt;）&lt;/p&gt;
&lt;p&gt;call是用来指挥回调函数&lt;code&gt;handle_call/3&lt;/code&gt;干活的。具体形式为
&lt;code&gt;handle_call(Request, From, State)&lt;/code&gt;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;第一个参数&lt;code&gt;Request&lt;/code&gt;是由call传进来的，是写程序时关注和处理的重点。&lt;/li&gt;
&lt;li&gt;第二个参数&lt;code&gt;From&lt;/code&gt;是gen_server传进来的，是调用的来源，也就是哪个进程执行了call。
&lt;code&gt;From&lt;/code&gt;的形式是&lt;code&gt;{Pid, Ref}&lt;/code&gt;，&lt;code&gt;Pid&lt;/code&gt;是来源进程号，而&lt;code&gt;Ref&lt;/code&gt;是调用的标识，每一次调用
都不一样，用以区别。有了Pid，在需要向来源进程发送消息时就可以使用，但由于call
是有返回值的，一般使用返回值传递数据就好。&lt;/li&gt;
&lt;li&gt;第三个参数&lt;code&gt;State&lt;/code&gt;是服务器的状态，这是由init或是其他的handle函数生成的，可以根据需要进
行修改之后，再放回返回值中。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;call对应的回调函数&lt;code&gt;handle_call/3&lt;/code&gt;在正常情况下的返回值是&lt;code&gt;{reply, Reply, NewState}&lt;/code&gt;，
&lt;code&gt;Reply&lt;/code&gt;会作为call的返回值传递回去，&lt;code&gt;NewState&lt;/code&gt;则会作为服务器的状态。
另外还可以使用&lt;code&gt;{stop, Reasion, State}&lt;/code&gt;中止服务器运行，这比较少用。&lt;/p&gt;
&lt;p&gt;使用call要小心的是，&lt;strong&gt;两个服务器进程不能互相call&lt;/strong&gt;，不然会死锁。&lt;/p&gt;
&lt;h3 id="cast"&gt;cast
&lt;/h3&gt;&lt;p&gt;cast是没有返回值的调用，一般把它叫做通知。它是一个“异步”的调用，调用后会直接收到
&lt;code&gt;ok&lt;/code&gt;，无需等待回调函数执行完毕。&lt;/p&gt;
&lt;p&gt;它的形式是&lt;code&gt;gen_server:cast(ServerRef, Request)&lt;/code&gt;。参数含义
与call相同。由于不需要等待返回，所以没必要设置超时，没有第三个参数。&lt;/p&gt;
&lt;p&gt;在多节点的情况下，可以用&lt;code&gt;abcast&lt;/code&gt;，向各节点上的具有指定名字的服务进程发通知。
（奇怪的是为啥为不叫&lt;code&gt;multi_cast&lt;/code&gt;，明明长得跟&lt;code&gt;multi_call&lt;/code&gt;很像的）&lt;/p&gt;
&lt;p&gt;cast们对应的回调函数是&lt;code&gt;handle_cast/2&lt;/code&gt;，具体为：&lt;code&gt;handle_cast(Msg, State)&lt;/code&gt;。
第一个参数是由cast传进去的，第二个是服务器状态，和call类似，不多说。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;handel_cast/2&lt;/code&gt;的返回值通常是&lt;code&gt;{noreply, NewState}&lt;/code&gt;，这可以用来改变服务器状态，
或是&lt;code&gt;{stop, Reason, NewState}&lt;/code&gt;，这会停止服务器。通常来说，停止服务器的命令用
cast来实现比较多。&lt;/p&gt;
&lt;h3 id="原生消息"&gt;原生消息
&lt;/h3&gt;&lt;p&gt;原生消息是指不通过call或cast，直接发往服务器进程的消息，有些书上译成“带外消息”。
比方说网络套接字socket发来的消息、别的进程用!发过来的消息、跟服务器建立链接的进程死掉了，
发来&lt;code&gt;{'EXIT', Pid, Why}&lt;/code&gt;等等。一般写程序要尽量用API，不要直接用!向服务器进程发消息，
但对于socket一类的依赖于消息的应用，就不得不处理原生消息了。&lt;/p&gt;
&lt;p&gt;原生消息使用&lt;code&gt;handle_info/2&lt;/code&gt;处理，具体为&lt;code&gt;handle_info(Info, State)&lt;/code&gt;。其中Info是
发过来的消息的内容。回复和&lt;code&gt;handle_cast&lt;/code&gt;是一样的。&lt;/p&gt;
&lt;h1 id="停止服务器"&gt;停止服务器
&lt;/h1&gt;&lt;p&gt;上面介绍的handle函数返回{stop,&amp;hellip;}，就会使用回调函数&lt;code&gt;terminate/2&lt;/code&gt;进行扫尾工作。
典型的如关闭已打开的资源、文件、网络连接，打log做记录，通知别的进程“我要死啦”，
或是“信春哥，满血复活”：利用传进来的状态State重新启动服务器。&lt;/p&gt;
&lt;p&gt;最简单的就是啥都不干，返回ok就好了。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;参考资料和资源：&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="http://www.erlang.org/doc/man/gen_server.html" target="_blank" rel="noopener"
 &gt;gen_server的文档&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="http://www.erlang.org/doc/design_principles/gen_server_concepts.html" target="_blank" rel="noopener"
 &gt;OTP设计原则中gen_server的介绍&lt;/a&gt;&lt;/p&gt;
&lt;h4 id="更新2013年9月13日"&gt;更新(2013年9月13日)
&lt;/h4&gt;&lt;p&gt;虽然笔记跟抄书没啥区别, 但抄一遍总会加强记忆的, 所以还是贴出来.&lt;/p&gt;
&lt;p&gt;call 操作会阻塞, 而且有死锁的可能性, 用起来要小心.&lt;/p&gt;</description></item><item><title>初识Erlang，Hello World（4）</title><link>https://blog.cndenis.com/Erlang/2013/03/%E5%88%9D%E8%AF%86Erlang_Hello_World_4.html</link><pubDate>Sun, 24 Mar 2013 00:00:00 +0000</pubDate><guid>https://blog.cndenis.com/Erlang/2013/03/%E5%88%9D%E8%AF%86Erlang_Hello_World_4.html</guid><description>&lt;p&gt;前几节的Hello world都是自言自语，今天试试对着别人说。首先是在本机上各个进程之间，
然后是在网络上不同机器之间。&lt;/p&gt;
&lt;h2 id="进程间的消息单向接收"&gt;进程间的消息：单向接收
&lt;/h2&gt;&lt;p&gt;Erlang里可以很方便地创建进程，这种进程是超轻量级的，运行于erlang虚拟机内部的，
而与操作系统的进程管理无关的（也就是说你在任务管理器中只会见到一个Erlang进程），
Erlang内的进程创建开销很小，创建一个进程所需的时间仅为微秒级，内存消耗也很少，
一台机上运行数以千计的进程也没问题。&lt;/p&gt;
&lt;p&gt;进程之间使用消息进行通讯。示例如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hw15srv&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;receive&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nn"&gt;io&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Hello &lt;/span&gt;&lt;span class="si"&gt;~p&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;~n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hw15srv&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hw15&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;Pid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="n"&gt;hw15srv&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;Pid&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;alice&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;Pid&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Bob&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;}.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;hw15/0&lt;/code&gt;首先是使用&lt;code&gt;spawn&lt;/code&gt;命令启动了一个&lt;code&gt;hw15srv/0&lt;/code&gt;进程，。这个命令会返回
所启动的进程的pid，也就是进程的标识符。然后使用&lt;code&gt;!&lt;/code&gt;向它发送消息。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;spawn&lt;/code&gt;命令有几种用法，对于上例，以下几种方式都可以&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="n"&gt;hw15srv&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fun&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;hw15srv&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="nv"&gt;MODULE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hw15srv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;要注意的是，第三种用法（也叫MFA法，即模块、函数、参数法）进行调用的话，
这个被调用的函数（即示例中的&lt;code&gt;hw15srv&lt;/code&gt;) &lt;em&gt;必须要export出来&lt;/em&gt;，即便是写在同一个文件中。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;hw15srv/0&lt;/code&gt;的作用是接收其他进程给他发的消息，并显示出来。接收消息使用&lt;code&gt;receive&lt;/code&gt;，
格式有点象case，先是对收到的消息进行模式匹配，如果匹配的话，该项&lt;code&gt;-&amp;gt;&lt;/code&gt;后的语句。&lt;/p&gt;
&lt;p&gt;发送消息的进程和接收消息的进程需要协调好消息的格式，这段程序中，消息是一个元组，
元组的第一个元素是原子&lt;code&gt;name&lt;/code&gt;，（一般习惯中erlang中的元组的第一个元素用一个原子
作元组的命名），第二个元素是一个字符串。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;hw15srv/0&lt;/code&gt;用的是所谓尾递归服务器的写法，语句段的&lt;em&gt;最后一行&lt;/em&gt;写上递归函数名，
象这样的服务器一定要符合尾递归的要求，不然的话运行一段时间服务器就会把内存塞爆。&lt;/p&gt;
&lt;h2 id="进程间的消息相互对话"&gt;进程间的消息：相互对话
&lt;/h2&gt;&lt;p&gt;上一段程序中，&lt;code&gt;hw15srv/0&lt;/code&gt;是只收不发的，别人对它说什么，它都没有响应。如果需要
有回应的话，可以这么写：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hw16srv&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;receive&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;From&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nn"&gt;io&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Server receive: &lt;/span&gt;&lt;span class="si"&gt;~p&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;~n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;From&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Welcome, &amp;#34;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="nv"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;}},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hw16srv&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hw16&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;Pid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="n"&gt;hw16srv&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;Sid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;Pid&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;Sid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;alice&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;}},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;receive&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;Pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Msg&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nn"&gt;io&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Client receive: &lt;/span&gt;&lt;span class="si"&gt;~p&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;~n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Msg&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;用到的关键字和上一段程序是一样的：创建进程&lt;code&gt;spawn&lt;/code&gt;，发送消息&lt;code&gt;!&lt;/code&gt;，接收消息&lt;code&gt;receive&lt;/code&gt;，
区别仅在于消息的格式。本段程序在消息的前面加上客户端进程的pid，让服务端进程知道
消息是由哪个进程发过来的。Erlang似乎没有获知消息来源的机制，因此需要手工把发送方
的pid写到消息中，方便接收方使用。&lt;/p&gt;
&lt;p&gt;在&lt;code&gt;hw16/0&lt;/code&gt;中，使用了&lt;code&gt;self()&lt;/code&gt;来获得本进程的pid，然后本进程pid填到消息中，发给
服务端，然后等待服务端发过来的消息，收到后就显示出来。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;hw16srv/0&lt;/code&gt;中则是接收消息，然后提取对方发过来的名字，在前面加上&amp;quot;welcome&amp;quot;，然后
发回给客户端。&lt;/p&gt;
&lt;h2 id="进程间的消息rpc"&gt;进程间的消息：RPC
&lt;/h2&gt;&lt;p&gt;RPC是远程过程调用的缩写，也就是让另一个地方的程序帮你执行，然后把结果返回给你。
Erlang中的发送请求和等待回应可以封装为一个rpc/2的函数：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;rpc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;Pid&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nv"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;receive&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;Pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;Response&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hw16b&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;Pid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="n"&gt;hw16srv&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Reply&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rpc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;alice&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nn"&gt;io&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Client receive: &lt;/span&gt;&lt;span class="si"&gt;~p&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;~n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Reply&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;rpc/2把发送请求和等待回应包装起来，用起来更方便了&lt;/p&gt;
&lt;h2 id="进程间的消息引用"&gt;进程间的消息：引用
&lt;/h2&gt;&lt;p&gt;上面的rpc有个两个问题：第一个问题，是当传入的第一个参数不是一个pid，而是一个注
册了的进程名，信息虽然也能发出去，返回的信息却是pid而不是注册名，无法匹配
&lt;code&gt;{Pid, Response}&lt;/code&gt; ，因而函数会永远等待下去而不返回。第二个问题，如果本线程给远
方线程发送了几个请求，对方发回了几个回复，那就搞不清哪个回复是对应哪个请求的了。
解决这两个问题的方法是使用一个“引用”，如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;rpc2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;Ref&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;make_ref&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;Pid&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nv"&gt;Ref&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nv"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;receive&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;Ref&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Reply&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;Reply&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hw18srv&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;receive&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;From&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Ref&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nn"&gt;io&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Server receive: &lt;/span&gt;&lt;span class="si"&gt;~p&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;~n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;From&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;Ref&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Welcome, &amp;#34;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="nv"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;}},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hw16srv&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hw18&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;Pid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="n"&gt;hw18srv&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Reply&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rpc2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;alice&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nn"&gt;io&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Client receive: &lt;/span&gt;&lt;span class="si"&gt;~p&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;~n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Reply&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;rpc2/2&lt;/code&gt;就用了 &lt;code&gt;make_ref()&lt;/code&gt; 来生成一个唯一的“引用”，&lt;code&gt;make_ref/0&lt;/code&gt;生成的引用几乎
是不会重复的，文档上的说明是要2E82次调用之后才会发生重复，这实际上是不可能的。&lt;/p&gt;
&lt;p&gt;（在这里bs一下《Erlang编程指南》这本书的中文翻译，译得像机翻也就算了，错误还不少，
像这个82在那本书上就被写成了28，我看书时还在怀疑，现代计算机进行2E28次运算，
不就是几秒的事，这make_ref到底行不行。（在211页））&lt;/p&gt;
&lt;h4 id="更新2013年9月13日"&gt;更新(2013年9月13日)
&lt;/h4&gt;&lt;p&gt;像上面写的那个rpc函数是不带超时选项的, 这在实际代码中有可能会永远都不返回,
程序就卡住了, 要尽量避免这种情况, 可以在后面加上 &lt;code&gt;after&lt;/code&gt; 子句, 超时不候.&lt;/p&gt;</description></item><item><title>初识Erlang，Hello World（3）</title><link>https://blog.cndenis.com/Erlang/2013/03/%E5%88%9D%E8%AF%86Erlang_Hello_World_3.html</link><pubDate>Fri, 15 Mar 2013 00:00:00 +0000</pubDate><guid>https://blog.cndenis.com/Erlang/2013/03/%E5%88%9D%E8%AF%86Erlang_Hello_World_3.html</guid><description>&lt;p&gt;今天不只要对World说Hello，还要对别人说Hello&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Who&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nn"&gt;io&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Hello &lt;/span&gt;&lt;span class="si"&gt;~p&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;~n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Who&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;平平无奇的一个函数，对Who说Hello&lt;/p&gt;
&lt;p&gt;如果要对一组人说Hello，可以这么做：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hw10&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;L&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;hw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;X&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="nv"&gt;X&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nv"&gt;L&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hw10&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;L&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;ali&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;bob&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;cat&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hw10&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;L&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上面是用了列表解析的方法。&lt;/p&gt;
&lt;p&gt;也可以用lists:map，效果和上面是一样的&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hw11&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;L&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nn"&gt;lists&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="n"&gt;hw&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;L&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hw11&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;L&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;ali&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;bob&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;cat&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hw11&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;L&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;另一个很相似的做法是lists:foreach：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hw14&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;L&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nn"&gt;lists&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;foreach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="n"&gt;hw&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;L&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hw14&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;L&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;ali&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;bob&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;cat&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hw14&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;L&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这两种做法有什么区别呢？看看输出：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erl" data-lang="erl"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;helloworld&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;hw11&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;Hello&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;ali&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;Hello&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;bob&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;Hello&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;cat&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;helloworld&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;hw14&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;Hello&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;ali&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;Hello&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;bob&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;Hello&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;cat&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ok&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;虽然map和foreach都是把同一个函数作用在列表的每一个元素上，
map是会生成一个新的列表来存储结果并返回，（由于hw/1的值就是ok，所以会得到包含3个ok的列表）
而foreach仅会返回ok。&lt;/p&gt;
&lt;p&gt;不使用Lists模块的话，可以这么做：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hw12&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nv"&gt;H&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="nv"&gt;T&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;H&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hw12&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;T&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hw12&lt;/span&gt;&lt;span class="p"&gt;([])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hw12&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;L&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;ali&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;bob&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;cat&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hw12&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;L&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这是Erlang中最常见的Head|Tail写法了吧。&lt;/p&gt;
&lt;p&gt;也可以用case改写上面的函数&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hw13&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;L&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nv"&gt;L&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;H&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="nv"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;hw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;H&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hw13&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hw13&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;L&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;ali&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;bob&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;cat&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hw13&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;L&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="更新2013年9月13日"&gt;更新(2013年9月13日)
&lt;/h4&gt;&lt;p&gt;如果数组很大, &lt;code&gt;lists:foreach/1&lt;/code&gt;占用的内存会比&lt;code&gt;lists:map/1&lt;/code&gt;少一些,
因为不需要生成一个同样大小的数组进行返回. 因此, 如果不需要返回值的话,
应该用&lt;code&gt;lists:foreach/1&lt;/code&gt;, 或者&lt;code&gt;lists:foldl/3&lt;/code&gt;, 或是自己写尾递归.&lt;/p&gt;</description></item><item><title>初识Erlang，Hello World (1)</title><link>https://blog.cndenis.com/Erlang/2013/03/%E5%88%9D%E8%AF%86Erlang_Hello_World.html</link><pubDate>Tue, 12 Mar 2013 00:00:00 +0000</pubDate><guid>https://blog.cndenis.com/Erlang/2013/03/%E5%88%9D%E8%AF%86Erlang_Hello_World.html</guid><description>&lt;p&gt;这两天开始玩Erlang，咱们从Hello World开始吧。&lt;/p&gt;
&lt;p&gt;先是要到官网&lt;a class="link" href="http://www.erlang.org/download.html" target="_blank" rel="noopener"
 &gt;http://www.erlang.org/download.html&lt;/a&gt;下载安装包，安装上，设置好系
PATH，然后打开命令行，输入&lt;code&gt;erl&lt;/code&gt;，如果看到类似于&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Eshell V5.10.1 (abort with ^G)
1&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;的话，就表示Erlang安装成功。这东西叫做Erlang的Shell。&lt;/p&gt;
&lt;p&gt;然后就是最经典的Hello World：&lt;/p&gt;
&lt;p&gt;随便用一个文本编辑器输入：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;helloworld&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;export&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;hw&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hw&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;io&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Hello World! &lt;/span&gt;&lt;span class="si"&gt;~n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;保存为helloworld.erl，然后在命令行下进入该文件所在目录，进入Erlang Shell，输
入&lt;code&gt;&amp;gt;&lt;/code&gt;后的命令：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erl" data-lang="erl"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;helloworld&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;helloworld&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;helloworld&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;hw&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;Hello&lt;/span&gt; &lt;span class="nv"&gt;World&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ok&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Yeah，Hello World完成！（我会告诉你我用了20分钟干这事么，下面是各种坑的介绍）&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c"&gt;% 首先，Erlang的注释符是百分号哦
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;helloworld&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c"&gt;% -module是必要的，这可不是Bash或Python，上来就可以Echo或Print
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c"&gt;% 然后，helloworld 必须与文件名相同（除了不用加.erl）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c"&gt;% 然后，行末的句点是必须的，虽然好不显眼
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;export&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;hw&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c"&gt;% -export也是必须的，这是用来说明哪些函数可以在外部被调用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c"&gt;% 括号中必须是一个列表，换言之，加方括号
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c"&gt;% hw是函数名，斜杠后面是参数的数目，两者总是组合指明一个函数。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c"&gt;% 参数数目不同的，即使同名，也是两个不同的函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c"&gt;% 还是记得句尾要加点
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hw&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;io&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Hello World! &lt;/span&gt;&lt;span class="si"&gt;~n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c"&gt;% 这个是函数了
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c"&gt;% 函数名前面不用任何修饰，类似于其他语言中的Fun，def之类在这里是不必要的
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c"&gt;% 函数名是一个“原子”，换言之就是一个以小写字母开头的单词，可后继大小写字母下划线和@号
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c"&gt;% 或是你足够蛋疼的话，可以用单引号括起来的任意东西，比方说 &amp;#39;*&amp;amp;^%hw2&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c"&gt;% 还有，不要拿fun当函数名，这个词另有用途
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c"&gt;% 函数名后面加括号，如果有参数，写在括号中
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c"&gt;% 括号后是 -&amp;gt; 这不是C语言中的指针，而是表示后面是函数的内容了
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c"&gt;% io:format可以当print，其实就是io模块里的format函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c"&gt;% 看清楚模块名和函数名之间是冒号，别弄成其他语言中的点
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c"&gt;% 双引号中是字符串，Erlang中的字符串实质上是数组
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c"&gt;% ~n是换行，用波浪线转义
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c"&gt;% 最后还是别忘记了是句点
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个erl文件的坑说完了，然后是Erlang Shell中的。&lt;/p&gt;
&lt;p&gt;想用erl xxxxx.erl来执行是徒劳的，这货不是sh也不是python也不是pl，这么做你会
进入Erlang Shell。&lt;/p&gt;
&lt;p&gt;然后先是要&lt;code&gt;c(helloworld).&lt;/code&gt;编译，记得不要忘记句点。然后同一个目录下就会出现一个
同名的beam文件。&lt;/p&gt;
&lt;p&gt;然后键入&lt;code&gt;helloworld:hw().&lt;/code&gt;，回车没反应？又忘记句点了，补上，Hello World终于蹦
出来了。&lt;/p&gt;</description></item><item><title>初识Erlang，Hello World (2)</title><link>https://blog.cndenis.com/Erlang/2013/03/%E5%88%9D%E8%AF%86Erlang_Hello_World-2.html</link><pubDate>Tue, 12 Mar 2013 00:00:00 +0000</pubDate><guid>https://blog.cndenis.com/Erlang/2013/03/%E5%88%9D%E8%AF%86Erlang_Hello_World-2.html</guid><description>&lt;p&gt;昨天费了老大劲终于把Hello World打出来了，今天我们继续。&lt;/p&gt;
&lt;h2 id="说n遍hello-world递归的使用"&gt;说N遍Hello World，递归的使用
&lt;/h2&gt;&lt;p&gt;Hello World说一遍怎么够呢，说N遍吧。代码如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;helloworld&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;export&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;hw3&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c"&gt;% 打印N遍Hello world
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hw3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;N&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="nv"&gt;N&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nn"&gt;io&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Hello World &lt;/span&gt;&lt;span class="si"&gt;~n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hw3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;N&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hw3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这有什么好坑的呢：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hw3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;N&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="nv"&gt;N&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;when后面是一个断言(guard)，仅在它为true时函数会被执行。&lt;/p&gt;
&lt;p&gt;断言所能使用的语句是受限的，不能用自定义的函数。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nn"&gt;io&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Hello World &lt;/span&gt;&lt;span class="si"&gt;~n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hw3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;N&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这一个函数体有多条语句，中间需要用逗号隔开&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hw3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;hw3/1这个函数有几个函数子句，根据参数的模式识别和when保护元的值来选择使用函数体。&lt;/p&gt;
&lt;p&gt;不同的函数体之间使用分号，最后一个末尾使用句点。&lt;/p&gt;
&lt;p&gt;啥都不干用什么好呢？&lt;a class="link" href="http://stackoverflow.com/questions/1126755/in-erlang-is-there-a-way-to-create-an-empty-function" target="_blank" rel="noopener"
 &gt;stackoverflow&lt;/a&gt;
上说用ok. 那就用ok吧。&lt;/p&gt;
&lt;h2 id="再说n遍hello-world使用case"&gt;再说N遍Hello World，使用case
&lt;/h2&gt;&lt;p&gt;如果不想用多个函数子句的话，可以用case&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hw5&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;N&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nv"&gt;N&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;X&lt;/span&gt; &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="nv"&gt;X&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nn"&gt;io&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Hello World &lt;/span&gt;&lt;span class="si"&gt;~n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hw5&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;N&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;case的语法是：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="err"&gt;条件表达式&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="err"&gt;模式&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="err"&gt;语句段&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="err"&gt;模式&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="err"&gt;语句段&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;....&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="err"&gt;模式&lt;/span&gt;&lt;span class="nv"&gt;N&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="err"&gt;语句段&lt;/span&gt;&lt;span class="nv"&gt;N&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;继续一行一行看：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nv"&gt;N&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;N是条件表达式，也就是说运行case中的哪一条子句会根据N的值来决定。&lt;/p&gt;
&lt;p&gt;只有一个子句会被执行，这点跟C语言不一样。&lt;/p&gt;
&lt;p&gt;而且如果全部子句的模式匹配都失败的话，会抛出错误。所以要考虑是否使用catch all的语句。&lt;/p&gt;
&lt;p&gt;条件表达式与子句之间是用of来分隔的，注意不要顺手打冒号了。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;X&lt;/span&gt; &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="nv"&gt;X&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;模式后面可以接when，也可以不用。&lt;/p&gt;
&lt;p&gt;这一行是这么运行的：首先是对X和N进行模式匹配，即&lt;code&gt;X=N&lt;/code&gt;，匹配是成功的，因为
变量X没有赋值，所以X绑定到N，然后由于保卫元&lt;code&gt;X&amp;gt;0&lt;/code&gt;为true，所以执行该子句。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nn"&gt;io&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Hello World &lt;/span&gt;&lt;span class="si"&gt;~n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hw5&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;N&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;注意模式与语句段之间是用 &lt;code&gt;-&amp;gt;&lt;/code&gt; 分开的，中间的case语句段需要以分号结束&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;递归结束条件，不可忘记的。最后一个case子句，也就是&lt;em&gt;end之前不需要加标点&lt;/em&gt;。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;case语句需要以end结束，后面这个句点是表示hw5整个函数的结束，不是case语法的一部分&lt;/p&gt;
&lt;h2 id="继续说hello-world使用if"&gt;继续说Hello World，使用if
&lt;/h2&gt;&lt;p&gt;if可以视为没有条件表达式和of的case&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hw6&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;N&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;N&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nn"&gt;io&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Hello World &lt;/span&gt;&lt;span class="si"&gt;~n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hw5&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;N&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;N&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ok&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;if的语法格式是：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="err"&gt;保护元&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="err"&gt;语句&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="err"&gt;保护元&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="err"&gt;语句&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.......&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="err"&gt;保护元&lt;/span&gt;&lt;span class="nv"&gt;N&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="err"&gt;语句&lt;/span&gt;&lt;span class="nv"&gt;N&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;if会执行第一个断言为真的语句。&lt;/p&gt;
&lt;p&gt;要注意的东西跟case没什么区别，就不啰嗦了。&lt;/p&gt;
&lt;h2 id="继续hello-world使用列表解析"&gt;继续Hello World，使用列表解析
&lt;/h2&gt;&lt;p&gt;这似乎是最简洁的做法了&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hw7&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;N&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;hw&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="p"&gt;_&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nn"&gt;lists&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;seq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;N&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;].&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这句话换相当于Python中的 [hw() for _ in range(1, N + 1)]。&lt;/p&gt;
&lt;p&gt;意思是把（1，2，3&amp;hellip;N）中的每一个值都装到变量_之后，运行hw()。由于hw中不调用
seq中产生的值，所以拿_这样的一个坑来装。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;lists:seq&lt;/code&gt;是产生一个连接序列的数组，与Python中的range不同的是，它是既包头又包
尾的，也是就说产生（1，2，3&amp;hellip;N）。&lt;/p&gt;
&lt;h2 id="继续hello-world山寨for"&gt;继续Hello World，山寨for
&lt;/h2&gt;&lt;p&gt;Erlang最令人觉得奇怪的是它没有循环语句，不过这不妨碍我们直接山寨一个。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-erlang" data-lang="erlang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;I&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;N&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;F&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="nv"&gt;I&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;N&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;F&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;I&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;N&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;F&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;N&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;N&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;F&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;F&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hw8&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;N&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;N&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="n"&gt;hw&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hw9&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;N&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;N&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;hw&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个山寨的for用了高阶函数的概念，它的F参数是是一个函数。注意&lt;code&gt;hw8/1&lt;/code&gt;和&lt;code&gt;hw9/1&lt;/code&gt;中
的写法，我碰壁了好久，后来问了程序老大才解决的。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;hw8/1&lt;/code&gt;是把函数名当参数后用，必须要使用fun关键词，而且要指明函数的目数，
这与Python不一样。Python一个函数名只能绑定一个函数，给出名字就唯一确定了绑定
对象。而Erlang允许同名不同目的函数，所以要指明目数。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;hw9/1&lt;/code&gt;则是产生一个匿名函数作为参数，注意匿名函数的写法。以fun作为函数名，
其余跟一般函数没什么区别。注意fun后面的括号不要漏掉，即使没有参数。&lt;/p&gt;
&lt;h4 id="更新2013年9月13日"&gt;更新(2013年9月13日)
&lt;/h4&gt;&lt;p&gt;函数匹配是有顺序的, 像这篇最开头的&lt;code&gt;hw/3&lt;/code&gt;, 如果把&lt;code&gt;hw3(0)&lt;/code&gt;写在前面,
就可以不需要&lt;code&gt;when N &amp;gt; 0&lt;/code&gt;了. 但这么做代码并不健壮, 遇上 N&amp;lt;0 就会出死循环.
因此, 还是加上&lt;code&gt;when N &amp;gt; 0&lt;/code&gt;吧.&lt;/p&gt;</description></item><item><title>我的 Sublime Text2 配置</title><link>https://blog.cndenis.com/Tools/2013/01/%E6%88%91%E7%9A%84Sublime_Text_2%E9%85%8D%E7%BD%AE.html</link><pubDate>Fri, 25 Jan 2013 00:00:00 +0000</pubDate><guid>https://blog.cndenis.com/Tools/2013/01/%E6%88%91%E7%9A%84Sublime_Text_2%E9%85%8D%E7%BD%AE.html</guid><description>&lt;p&gt;Sublime Text 2是最近很火的一个代码编辑器，我也跟风玩了一下，果然很好用。方便的插件管理器加上丰富的插件，可以很容易把它调教得很顺手。几乎每项功能都可以用鼠标和键盘两种方式来实现，方便各种习惯的人。Sublime Text 2 的介绍与推荐网上已经有很多，这里记一下我安装的包和配置。&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="http://wbond.net/sublime_packages/package_control" target="_blank" rel="noopener"
 &gt;Package Control&lt;/a&gt;
&lt;em&gt;(因为这东西在后台更新曾经导致我的Sublime完全崩溃, 已经弃用)&lt;/em&gt;&lt;/p&gt;
&lt;strike&gt;
包管理器是必备的，新下载的Sublime Text 2 第一个装的肯定是这个，有了它，装其他的包就很方便了。
&lt;p&gt;安装方式有两种，第一种是在线下载安装：在 Sublime Text 2 中按下&lt;code&gt;ctrl+`&lt;/code&gt;（就是大键盘数字1左边的那个键），拷贝以下命令到窗口下部的终端中，&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;urllib2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="nn"&gt;os&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;pf&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Package Control.sublime-package&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;ipp&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;sublime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;installed_packages_path&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;makedirs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ipp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ipp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;urllib2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;install_opener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;urllib2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;build_opener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;urllib2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ProxyHandler&lt;/span&gt;&lt;span class="p"&gt;()));&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ipp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;pf&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;wb&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;urllib2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;urlopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;http://sublime.wbond.net/&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;pf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;%20&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Please restart Sublime Text to finish installation&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;回车运行，重启 Sublime Text 2，即可。另一种方法是手动安装，看&lt;a class="link" href="http://wbond.net/sublime_packages/package_control/installation" target="_blank" rel="noopener"
 &gt;这里&lt;/a&gt;，个人觉得不太必要，在没有网络的环境下，包管理器也没什么用了。&lt;/p&gt;
&lt;p&gt;在安装完包管理器之后，只要按下&lt;code&gt;ctrl+shift+p&lt;/code&gt;，输入&lt;code&gt;ip&lt;/code&gt;，选择“Package Control: Install Package”，然后输入要安装的包的名称，就可以在线安装了。
&lt;/strike&gt;&lt;/p&gt;
&lt;ol start="2"&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://github.com/buymeasoda/soda-theme/" target="_blank" rel="noopener"
 &gt;Soda&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这是个主题，也就是Sublime自身的皮肤，比自带的要漂亮一些。在包管理器中装上之后，打开配置文件&lt;code&gt;Preferences&lt;/code&gt; -&amp;gt; &lt;code&gt;Settings - User&lt;/code&gt;，加上一行&lt;code&gt;&amp;quot;theme&amp;quot;: &amp;quot;Soda Light.sublime-theme&amp;quot;&lt;/code&gt;或者 &lt;code&gt;&amp;quot;theme&amp;quot;: &amp;quot;Soda Dark.sublime-theme&amp;quot;&lt;/code&gt;。前面一个是亮色主题，后面一个是暗色主题。我喜欢暗色，看起来比较有黑客的调调。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="http://madeofcode.com/posts/29" target="_blank" rel="noopener"
 &gt;Made of code&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这个是代码高亮方案。包管理器中没有这个方案，官网似乎要翻墙才能上，国内可以在&lt;a class="link" href="https://github.com/kumarnitin/made-of-code-tmbundle/tree/master/Themes" target="_blank" rel="noopener"
 &gt;这里&lt;/a&gt;下载。把下载到的&lt;code&gt;Made of Code.tmTheme&lt;/code&gt;放到Sublime Text 2的安装目录下的&lt;code&gt;Data\Packages\Color Scheme - Default&lt;/code&gt;文件夹，然后就可以在&lt;code&gt;Preferences&lt;/code&gt; -&amp;gt; &lt;code&gt;Color Scheme&lt;/code&gt;选择&lt;code&gt;made of code&lt;/code&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://github.com/erinata/SublimeMarkdownBuild" target="_blank" rel="noopener"
 &gt;Markdown Build&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://github.com/revolunet/sublimetext-markdown-preview" target="_blank" rel="noopener"
 &gt;MarkDown preview&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这两个是写Markdown必备的。可以在包管理器中安装。装完之后，写作Markdown时（右下角显示语法为Markdown），可以按&lt;code&gt;ctrl+b&lt;/code&gt;，直接就会生成HTML，并在浏览器中显示。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://github.com/jonschlinkert/sublime-markdown-extended" target="_blank" rel="noopener"
 &gt;sublime-markdown-extended&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这个是用来支持放在Markdown文件头部的yaml信息的代码高亮, 便于使用jekyll写Blog.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://github.com/titoBouzout/SideBarEnhancements" target="_blank" rel="noopener"
 &gt;SideBarEnhancements&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这是用来增强左边的侧边栏。左侧边栏可以在&lt;code&gt;View&lt;/code&gt; -&amp;gt; &lt;code&gt;Side Bar&lt;/code&gt; -&amp;gt; &lt;code&gt;Show Side Bar&lt;/code&gt;中打开，可以用&lt;code&gt;Project&lt;/code&gt; -&amp;gt; &lt;code&gt;Add Folder to Project...&lt;/code&gt;往侧边栏加入常用的文件夹。装完这个插件，侧边栏的右键菜单会多一些功能，挺实用的。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://github.com/SublimeLinter/SublimeLinter" target="_blank" rel="noopener"
 &gt;SublimeLinter&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这是用来在写代码时做代码检查的。可以在包管理器中安装。写Python程序的话，它还会帮你查代码是否符合&lt;a class="link" href="http://www.python.org/dev/peps/pep-0008/" target="_blank" rel="noopener"
 &gt;PEP8&lt;/a&gt;的要求。有问题有代码会出现白框，点击时底下的状态栏会提示出什么问题。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://bitbucket.org/StephaneBunel/pythonpep8autoformat" target="_blank" rel="noopener"
 &gt;Python PEP8 Autoformat&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这是用来按PEP8自动格式化代码的。可以在包管理器中安装。如果以前写程序不留意的话，用SublimeLinter一查，满屏都是白框框，只要装上这个包，按&lt;code&gt;ctrl+shift+r&lt;/code&gt;，代码就会按PEP8要求自动格式化了，一屏的白框几乎都消失了。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://github.com/akira-cn/sublime-gbk" target="_blank" rel="noopener"
 &gt;gbk&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;听说Sublime Text 2读GBK编码的文件会乱码，所以我早早就把这个给装上了，没见过乱码，不知管用不。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://github.com/facelessuser/BracketHighlighter" target="_blank" rel="noopener"
 &gt;Bracket Highlighter&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这是用来做括号匹配高亮的，可以在包管理器中安装。Sublime Text 2自带的括号匹配只有小小的一横线，太不显眼了，这个可以让高亮变成大大的一坨，不过我觉得它大得会盖住光标了。&lt;em&gt;(现在已经不用了)&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="http://wbond.net/sublime_packages/terminal" target="_blank" rel="noopener"
 &gt;Terminal&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这是用来在当前文件所在位置打开终端的。可以在包管理器中安装。对于Windows用户，安装完后，要先在&lt;code&gt;Preferences&lt;/code&gt; -&amp;gt; &lt;code&gt;Package Setting&lt;/code&gt; -&amp;gt; &lt;code&gt;Terminal&lt;/code&gt; -&amp;gt; &lt;code&gt;Settings - Default&lt;/code&gt;里，设置&lt;code&gt;&amp;quot;terminal&amp;quot;: &amp;quot;cmd&amp;quot;,&lt;/code&gt;。（如果喜欢用ipython的话，也可以改为ipython）之后只要按下&lt;code&gt;ctrl+shift+t&lt;/code&gt;，即可在当前文件位置打开命令行窗口。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://github.com/wbond/sublime_alignment" target="_blank" rel="noopener"
 &gt;Alignment&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;用来做代码对齐的, 最主要是做等号对齐. 我的设置把默认快捷键取消掉, 自定义为
&lt;code&gt;{ &amp;quot;keys&amp;quot;: [&amp;quot;alt+a&amp;quot;], &amp;quot;command&amp;quot;: &amp;quot;alignment&amp;quot; }&lt;/code&gt;,
按&lt;code&gt;alt+a&lt;/code&gt;进行等号对齐.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://github.com/kemayo/sublime-text-2-goto-documentation" target="_blank" rel="noopener"
 &gt;Goto Documentation&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这是用来快速查文档的, 我的设置把默认快捷键取消掉, 自定义为 &lt;code&gt;{&amp;quot;keys&amp;quot;: [&amp;quot;f1&amp;quot;], &amp;quot;command&amp;quot;: &amp;quot;goto_documentation&amp;quot;}&lt;/code&gt;, 按F1就可以跳转到光标位置的文件.&lt;/p&gt;
&lt;p&gt;我把这个插件Fork出来改了几行, 添加了对 Erlang 的支持, 在&lt;a class="link" href="https://github.com/cnDenis/sublime-text-2-goto-documentation" target="_blank" rel="noopener"
 &gt;这里&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://github.com/srusskih/SublimeJEDI" target="_blank" rel="noopener"
 &gt;SublimeJEDI&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这个似乎是目前ST2上最好用的Python代码补全插件, 不过它的快捷键默认设置比较坑爹, 我全部取消掉, 具体设置看我的 GIST: &lt;a class="link" href="https://gist.github.com/cnDenis/6525289" target="_blank" rel="noopener"
 &gt;键盘设置&lt;/a&gt; 和 &lt;a class="link" href="https://gist.github.com/cnDenis/6525329" target="_blank" rel="noopener"
 &gt;鼠标设置&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://github.com/kairyou/SublimeTmpl" target="_blank" rel="noopener"
 &gt;SublimeTmpl&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;新建文件时的模板, &lt;a class="link" href="https://gist.github.com/cnDenis/6525289" target="_blank" rel="noopener"
 &gt;我的GIST&lt;/a&gt;里有在不同语法环境下打开不同模板文件的设置. 对于经常要在多种语言下工具的人比较方便&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://github.com/fjl/Sublime-Erlang" target="_blank" rel="noopener"
 &gt;Sublime-Erlang&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://github.com/ostinelli/SublimErl" target="_blank" rel="noopener"
 &gt;Sublimerl&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这两个是用ST2写Erlang代码必备插件, 前一个提供了更好的语方高亮等支持, 需要禁用掉Sublime自带的Erlang插件.
后一个提供了代码补全功能, 可恶的是原作者人为不支持Windows, 所以我自己&lt;a class="link" href="https://github.com/cnDenis/SublimErl" target="_blank" rel="noopener"
 &gt;Fork了一份&lt;/a&gt;, 添加了对Windows的支持.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;我还安装了另外的一些包，还没怎么用，这里就不详细介绍了：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/welefen/KeymapManager" target="_blank" rel="noopener"
 &gt;KeymapManager&lt;/a&gt; 插件快捷键管理，快捷键&lt;code&gt;ctrl+alt+k&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/clintberry/sublime-text-2-ini" target="_blank" rel="noopener"
 &gt;INI file Syntax Highlighting&lt;/a&gt; ini文件代码高亮&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/colinta/ApacheConf.tmLanguage" target="_blank" rel="noopener"
 &gt;ApacheConf.tmLanguage&lt;/a&gt; Apache配置文件代码高亮&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/stuartherbert/sublime-phpsnippets" target="_blank" rel="noopener"
 &gt;sublime-phpsnippets&lt;/a&gt; 更多的一些PHP代码补全&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/SublimeText/jQuery" target="_blank" rel="noopener"
 &gt;jQuery&lt;/a&gt; jQuery&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/SublimeText/Tag" target="_blank" rel="noopener"
 &gt;Tag&lt;/a&gt; HTML标签补完、格式化&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;还有一些我装了又删掉的包，不是说它们做得不好，而是我不喜欢或是在我的机上莫明运行不能，不折腾了。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/dreadatour/Pep8Lint" target="_blank" rel="noopener"
 &gt;Pep8Lint&lt;/a&gt; PEP8检查，其实用SublimeLinter检查就够了&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/Kronuz/SublimeCodeIntel" target="_blank" rel="noopener"
 &gt;SublimeCodeIntel&lt;/a&gt; 代码补全，这东西上百兆的巨大体积就不说了，问题是在我的比较大的代码文件上工作不正常，不知怎么办。反正Sublime Text 2本身也自带一点代码补完功能，这个不用也罢了。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Sublime Text 2 我最常用快捷键是以下几个：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ctrl+p&lt;/code&gt; 跳转到任意文件&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ctrl+r&lt;/code&gt; 快速定位到指定类/函数/标题&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ctrl+g&lt;/code&gt; 快速跳转到某一行号，在debug时很常用&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ctrl+d&lt;/code&gt; 多处选择, 绝对的&lt;strong&gt;神器&lt;/strong&gt;!&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ctrl+b&lt;/code&gt; build&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ctrl+shift+t&lt;/code&gt; 在当前位置打开终端（需安装terminal）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ctrl+shift+r&lt;/code&gt; 按PEP8格式化代码（需安装Python PEP8 Autoformat）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ctrl+shift+p&lt;/code&gt; 基本上啥功能都在里面了&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;还有 &lt;code&gt;ctrl+s&lt;/code&gt;、&lt;code&gt;ctrl+a&lt;/code&gt;、&lt;code&gt;ctrl+z&lt;/code&gt;、&lt;code&gt;ctrl+x&lt;/code&gt;、&lt;code&gt;ctrl+c&lt;/code&gt;、&lt;code&gt;ctrl+v&lt;/code&gt;这些和其他软件一样，就不用多说了&lt;/p&gt;
&lt;p&gt;Sublime Text 2 的配置文件的修改可以参考&lt;a class="link" href="http://www.feelcss.com/sublime-text-2-settings.html" target="_blank" rel="noopener"
 &gt;Sublime Text 2 设置文件详解&lt;/a&gt;。默认其实已经挺好，我是在&lt;code&gt;Preferences&lt;/code&gt; -&amp;gt; &lt;code&gt;Setting User&lt;/code&gt;加了这几行：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;default_line_ending&amp;#34;&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;unix&amp;#34;&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;rulers&amp;#34;&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;78&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;translate_tabs_to_spaces&amp;#34;&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;分别是用来设定行尾换行符、显示长行标尺和按tab输出空格。&lt;/p&gt;
&lt;p&gt;另外有一个很实用的设置，在括号中使用Enter跳出括号，在&lt;code&gt;Preferences&lt;/code&gt; -&amp;gt; &lt;code&gt;Key Bindings User&lt;/code&gt;中加上&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nt"&gt;&amp;#34;keys&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;enter&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;command&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;move&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;args&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nt"&gt;&amp;#34;by&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;characters&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;forward&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;context&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;key&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;following_text&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;operator&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;regex_contains&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;operand&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;^[)\\]\\&amp;gt;\\&amp;#39;\\\&amp;#34;\\ %&amp;gt;\\}\\;\\,]&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;match_all&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;key&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;preceding_text&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;operator&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;not_regex_match&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;operand&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;^.*\\{$&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;match_all&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;key&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;auto_complete_visible&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;operator&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;equal&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;operand&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;暂时先这么多，以后再补充吧。&lt;/p&gt;
&lt;p&gt;参考：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="http://lucifr.com/2011/08/31/sublime-text-2-tricks-and-tips/" target="_blank" rel="noopener"
 &gt;Sublime Text 2 入门及技巧&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="http://timewilltell.me/node/15" target="_blank" rel="noopener"
 &gt;配置Sublime Text使用Markdown，语法高亮,生成HTML&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="http://www.qianduan.net/essential-to-sublime-the-text-2-plugins.html" target="_blank" rel="noopener"
 &gt;一些必不可少的Sublime Text 2插件&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="http://www.feelcss.com/sublime-text-2-settings.html" target="_blank" rel="noopener"
 &gt;Sublime Text 2 设置文件详解&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="http://ruby-china.org/topics/4824" target="_blank" rel="noopener"
 &gt;sublime 怎样跳出括号？&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="更新后记废话2013年9月12日"&gt;更新+后记+废话(2013年9月12日):
&lt;/h4&gt;&lt;p&gt;现在已经不用 Package Control 了, 其实 ST2 的插件多数都在 Github上, 自己上去找插件, 放到 Packages 文件夹里就好, 用 Github 进行升级和管理, 比什么都好.&lt;/p&gt;
&lt;p&gt;这篇文章是1月份写的, 最初是放在&lt;a class="link" href="cndenis.iteye.com" &gt;我的iteye博客&lt;/a&gt;上的. ST2 从年初用到现在, 我从业余码农变成职业码农, 重装过一两回ST2, 增减了一些插件. 之前主要是用来写 Python, 现在还要兼顾 Erlang/ PHP/ JavaScript/ HTML, 还有于是又多了一些插件. 主要的加到上面去了.&lt;/p&gt;
&lt;p&gt;ST2的插件十分丰富的. 刚开始玩的人, 尤其是装上了 Package Control 这么方便的东西之后, 可能会使劲地往里头装东西. 但用过一段时间会发现, 很多插件其实并不太用得上, 装多了反而会造成快捷键冲突/影响运行速度和稳定性的问题, 于是就会想着去精简一些插件. 这和折腾其它的东西也是很像的, 从简陋到臃肿, 再到简约.&lt;/p&gt;
&lt;p&gt;ST2本身强大的功能配合丰富的插件, 使我可以把它变成一个大一统的IDE, 写啥代码都用它, 统一操作习惯, 很爽.&lt;/p&gt;
&lt;p&gt;ST2的插件是十分自由的, 有点 Python 基础的都可以自己折腾着玩, 我自己都Fork过几个, 按着自己的需要改来用. 我想, 喜欢折腾和喜欢造轮子的人, 大概都会喜欢上它吧.&lt;/p&gt;</description></item><item><title>Python2.x中支持unicode的configparser</title><link>https://blog.cndenis.com/Python/2013/01/Python2.x%E4%B8%AD%E6%94%AF%E6%8C%81unicode%E7%9A%84configparser.html</link><pubDate>Wed, 16 Jan 2013 00:00:00 +0000</pubDate><guid>https://blog.cndenis.com/Python/2013/01/Python2.x%E4%B8%AD%E6%94%AF%E6%8C%81unicode%E7%9A%84configparser.html</guid><description>&lt;p&gt;Python2.x中许多内置模块不支持unicode，确实是很烦的事。configparser就是其中之一。&lt;/p&gt;
&lt;p&gt;解决方法是使用Python3.x中configparser的backport，&lt;a class="link" href="http://pypi.python.org/pypi/configparser" target="_blank" rel="noopener"
 &gt;http://pypi.python.org/pypi/configparser&lt;/a&gt;，下载后解压，把其中的&lt;code&gt;configparser.py&lt;/code&gt;和&lt;code&gt;configparser_helpers.py&lt;/code&gt;放到你的代码所在文件夹中。然后在import时把&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;ConfigParser&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;改成&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;configparser&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;就可以了。&lt;/p&gt;
&lt;p&gt;参考：&lt;a class="link" href="http://bugs.python.org/issue11597" target="_blank" rel="noopener"
 &gt;http://bugs.python.org/issue11597&lt;/a&gt;&lt;/p&gt;</description></item><item><title>解决Ulipad和有道词典冲突的问题</title><link>https://blog.cndenis.com/Tools/2013/01/%E8%A7%A3%E5%86%B3Ulipad%E5%92%8C%E6%9C%89%E9%81%93%E8%AF%8D%E5%85%B8%E5%86%B2%E7%AA%81%E7%9A%84%E9%97%AE%E9%A2%98.html</link><pubDate>Mon, 14 Jan 2013 00:00:00 +0000</pubDate><guid>https://blog.cndenis.com/Tools/2013/01/%E8%A7%A3%E5%86%B3Ulipad%E5%92%8C%E6%9C%89%E9%81%93%E8%AF%8D%E5%85%B8%E5%86%B2%E7%AA%81%E7%9A%84%E9%97%AE%E9%A2%98.html</guid><description>&lt;p&gt;Ulipad和目前版本的有道词典有冲突，表现为先开有道词典，Ulipad就无法运行。&lt;/p&gt;
&lt;p&gt;解决方法是：找到Ulipad安装目录下的config.ini，添加以下两行：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ini" data-lang="ini"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;[server]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;50001&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;重启Ulipad，就不冲突了。&lt;/p&gt;
&lt;p&gt;原因是Ulipad通过绑定指定端口来避免重复运行，而这个端口恰好与有道使用的端口一致。只要选一个未被其他软件使用的端口，就可以解决问题。&lt;/p&gt;
&lt;p&gt;参考：&lt;a class="link" href="http://code.google.com/p/ulipad/issues/detail?id=306" target="_blank" rel="noopener"
 &gt;http://code.google.com/p/ulipad/issues/detail?id=306&lt;/a&gt;， Ulipad FAQ.htm文件&lt;/p&gt;</description></item><item><title>利用tkFileDialog.askopenfilenames获取多个文件名</title><link>https://blog.cndenis.com/Python/2012/12/%E5%88%A9%E7%94%A8tkFileDialog.askopenfilenames%E8%8E%B7%E5%8F%96%E5%A4%9A%E4%B8%AA%E6%96%87%E4%BB%B6%E5%90%8D.html</link><pubDate>Thu, 27 Dec 2012 00:00:00 +0000</pubDate><guid>https://blog.cndenis.com/Python/2012/12/%E5%88%A9%E7%94%A8tkFileDialog.askopenfilenames%E8%8E%B7%E5%8F%96%E5%A4%9A%E4%B8%AA%E6%96%87%E4%BB%B6%E5%90%8D.html</guid><description>&lt;p&gt;用Python写小脚本，要选择文件，最简单的方式莫过于使用内置的Tk的控件了。如果需要同时选择多个文件，可以使用&lt;code&gt;tkFileDialog.askopenfilenames&lt;/code&gt;，如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;tkFileDialog&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;fns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tkFileDialog&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;askopenfilenames&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filetypes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;text file&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;*.txt&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;all&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;*.*&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;repr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fns&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;但问题是，在Python 2.6以后的版本，&lt;code&gt;tkFileDialog.askopenfilenames&lt;/code&gt;返回的居然是字符串，类似于这样：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sa"&gt;u&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;C:/Python27/LICENSE.txt C:/Python27/NEWS.txt C:/Python27/README.txt&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果每个文件的路径中都没有空格，用&lt;code&gt;fps.split()&lt;/code&gt;就可以分解字符串得到文件名的列表，如果文件名或文件路径中包含空格，这个字符串将很不好解析。解决方法如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Tkinter&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;tkFileDialog&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;master&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Tkinter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tk&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;master&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;withdraw&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;# 不显示界面主窗口&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;fnstr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tkFileDialog&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;askopenfilenames&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filetypes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;text file&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;*.txt&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;all&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;*.*&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;fns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;master&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;splitlist&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fnstr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# 把多个文件名字符串分割成元组&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;repr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fns&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这样得到的就是元组了，&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;C:/Python27/LICENSE.txt&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;C:/Python27/NEWS.txt&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;C:/Python27/README.txt&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后就可以用&lt;code&gt;for&lt;/code&gt;得到每个文件名了。&lt;/p&gt;
&lt;p&gt;如果文件名中包含中文，&lt;code&gt;Tkinter.Tk.tk.splitlist&lt;/code&gt;分割完后的文件名可能会不能用，需要先把文件名&lt;code&gt;encode&lt;/code&gt;后传进去，分割完再&lt;code&gt;decode&lt;/code&gt;。代码如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;sys&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;sysencode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getfilesystemencoding&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;fnsen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fnstr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sysencode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;fnss&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;master&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;splitlist&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fnsen&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;fns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;unicode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;sysencode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;fnss&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这样就可以了。&lt;/p&gt;
&lt;p&gt;以上内容参考了：&lt;a class="link" href="http://stackoverflow.com/questions/4116249/parsing-the-results-of-askopenfilenames" target="_blank" rel="noopener"
 &gt;Parsing the results of askopenfilenames()?&lt;/a&gt; 和 &lt;a class="link" href="http://bugs.python.org/issue5712" target="_blank" rel="noopener"
 &gt;tkinter - askopenfilenames returns string instead of tuple in windows 2.6.1 release&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Python 3.x中的nonlocal及其在2.x中的变通办法</title><link>https://blog.cndenis.com/Python/2012/12/Python3.x%E4%B8%AD%E7%9A%84nonlocal%E5%8F%8A%E5%85%B6%E5%9C%A82.x%E4%B8%AD%E7%9A%84%E5%8F%98%E9%80%9A%E5%8A%9E%E6%B3%95.html</link><pubDate>Wed, 26 Dec 2012 00:00:00 +0000</pubDate><guid>https://blog.cndenis.com/Python/2012/12/Python3.x%E4%B8%AD%E7%9A%84nonlocal%E5%8F%8A%E5%85%B6%E5%9C%A82.x%E4%B8%AD%E7%9A%84%E5%8F%98%E9%80%9A%E5%8A%9E%E6%B3%95.html</guid><description>&lt;p&gt;在Python 2.x中，函数内部可以定义函数，内层的函数可以读取外层函数的局部变量，但却不可以修改它.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;outter&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;inner&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;inner is called, x=&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;inner&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;outter&lt;/span&gt;&lt;span class="p"&gt;()()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上面这个程序是没问题的，但是，下面这个就会出错：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;outter&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;inner&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;inner is called, x=&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;inner&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;outter&lt;/span&gt;&lt;span class="p"&gt;()()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;提示竟然是&lt;code&gt;UnboundLocalError: local variable 'x' referenced before assignment&lt;/code&gt;，找不到变量。&lt;/p&gt;
&lt;p&gt;这个错误在Python 3.x中的解决方法是使用Py3k新增的关键词&lt;code&gt;nonlocal&lt;/code&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;outter&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;inner&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;nonlocal&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;inner is called, x=&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;inner&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;outter&lt;/span&gt;&lt;span class="p"&gt;()()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;但Python 2.x中没有这个关键词，怎么办呢？如果对变量的改变的不需要影响外层的话，可以新建一个变量来用也可以。&lt;/p&gt;
&lt;p&gt;新建变量的方式：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;outter&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;inner&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;inner is called, x=&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;inner&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;outter&lt;/span&gt;&lt;span class="p"&gt;()()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;由于y是在内层函数中定义的，可以随便改变，但外层函数看不见y。而如果需要内层对变量的改变被外层看到的话，变通的方法是使用可变的对象，例如dict、对像的属性等。例如 Python 3.x中的代码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;outter&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;inner&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;nonlocal&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;inner is called, x=&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;inner&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;outter after inner called, x=&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;outter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;#Python 3.3中输出：&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;#inner is called, x= 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;#outter after inner called, x= 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在Python 2.x中用dict的方式变通为：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;outter&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;inner&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;inner is called, x=&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;inner&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;outter after inner called, x=&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;outter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;#Python 2.7中输出：&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;#inner is called, x= 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;#outter after inner called, x= 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;用对像的属性的方式：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;C&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;pass&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;outter&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;inner&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;inner is called, x=&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;inner&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;outter after inner called, x=&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;outter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;#Python 2.7中输出：&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;#inner is called, x= 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;#outter after inner called, x= 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;以上内容参考了：&lt;a class="link" href="http://www.keakon.net/2009/10/15/Python%E7%9A%84%E9%97%AD%E5%8C%85%E4%B8%8Enonlocal" target="_blank" rel="noopener"
 &gt;Python的闭包与nonlocal&lt;/a&gt; 以及 &lt;a class="link" href="http://davidchambersdesign.com/simulating-nonlocal-in-python-2.x/" target="_blank" rel="noopener"
 &gt;Simulating nonlocal in Python 2.x&lt;/a&gt;&lt;/p&gt;</description></item><item><title>在 PyGraphviz 中使用中文</title><link>https://blog.cndenis.com/Python/2012/12/%E5%9C%A8PyGraphviz%E4%B8%AD%E4%BD%BF%E7%94%A8%E4%B8%AD%E6%96%87.html</link><pubDate>Tue, 18 Dec 2012 00:00:00 +0000</pubDate><guid>https://blog.cndenis.com/Python/2012/12/%E5%9C%A8PyGraphviz%E4%B8%AD%E4%BD%BF%E7%94%A8%E4%B8%AD%E6%96%87.html</guid><description>&lt;p&gt;在 PyGraphviz 使用中文要注意的：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;汉字要使用 unicode ，例如：&lt;code&gt;u&amp;quot;汉字&amp;quot;&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;添加节点时要指定中文的字体，例如 &lt;code&gt;fontname=SimSun&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;示例如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;pygraphviz&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nn"&gt;pg&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;G&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AGraph&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;G&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;u&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;经理&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fontname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;`Microsoft YaHei&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;rect&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;rounded&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fontsize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;#雅黑&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;G&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;u&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;秘书&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fontname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;SimHei&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;#黑体&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;G&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;u&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;小兵&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fontname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;SimSun&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;#宋体&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;G&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;u&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;小卒&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fontname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Kaiti&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;#楷体&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;G&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;u&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;经理&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sa"&gt;u&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;秘书&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;G&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;u&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;经理&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sa"&gt;u&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;小兵&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;G&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;u&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;秘书&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sa"&gt;u&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;小卒&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;G&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;draw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;test_pygraphviz.png&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;png&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prog&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;neato&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;输出效果如下：&lt;/p&gt;
&lt;img src="http://farm9.staticflickr.com/8486/8283114699_a3c32a6287_m.jpg" width="187" height="240" alt="test_pygraphviz"&gt;
&lt;p&gt;附几个常用的中文字体的英文名：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;黑体：SimHei&lt;/li&gt;
&lt;li&gt;宋体：SimSun&lt;/li&gt;
&lt;li&gt;仿宋：FangSong&lt;/li&gt;
&lt;li&gt;楷体：KaiTi&lt;/li&gt;
&lt;li&gt;微软雅黑体：Microsoft YaHei&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;更多字体英文名可参考： &lt;a class="link" href="http://www.aoao.org.cn/blog/2008/03/fonts-chinese/" target="_blank" rel="noopener"
 &gt;http://www.aoao.org.cn/blog/2008/03/fonts-chinese/&lt;/a&gt;&lt;/p&gt;</description></item><item><title>在Windows下安装pygraphviz</title><link>https://blog.cndenis.com/Python/2012/12/%E5%9C%A8Windows%E4%B8%8B%E5%AE%89%E8%A3%85pygraphviz.html</link><pubDate>Tue, 18 Dec 2012 00:00:00 +0000</pubDate><guid>https://blog.cndenis.com/Python/2012/12/%E5%9C%A8Windows%E4%B8%8B%E5%AE%89%E8%A3%85pygraphviz.html</guid><description>&lt;p&gt;用 pip 或是 easy_install 在Windows 下安装 pygraphviz，
会出现&lt;code&gt;OSError: Error locating graphviz.&lt;/code&gt;的错误。
解决方法如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;先下载并安装 Graphviz 。下载地址 &lt;a class="link" href="http://www.graphviz.org/Download_windows.php" target="_blank" rel="noopener"
 &gt;http://www.graphviz.org/Download_windows.php&lt;/a&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在 &lt;a class="link" href="http://pypi.python.org/pypi/pygraphviz/" target="_blank" rel="noopener"
 &gt;http://pypi.python.org/pypi/pygraphviz/&lt;/a&gt; 下载 pygraphviz 原代码，解压。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;修改 setup.py ,&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;找到&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;library_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;include_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;修改为&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;library_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;C:\Program Files\Graphviz 2.28\lib\release\lib&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;include_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;C:\Program Files\Graphviz 2.28\include\graphviz&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其中 &lt;code&gt;C:\Program Files\Graphviz 2.28&lt;/code&gt; 改为 Graphviz 的安装地址。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;修改 agraph.py , 在函数 &lt;code&gt;def_run_prog&lt;/code&gt; 中找到:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;runprog&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;修改为：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s1"&gt;&amp;#34;&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;runprog&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;在命令行中执行&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;安装完成。&lt;/p&gt;
&lt;p&gt;出处： &lt;a class="link" href="https://networkx.lanl.gov/trac/ticket/117" target="_blank" rel="noopener"
 &gt;https://networkx.lanl.gov/trac/ticket/117&lt;/a&gt;，原出处对&lt;code&gt;cmd&lt;/code&gt;行的修改是有错误的，这里修正了。&lt;/p&gt;</description></item><item><title>用Python解析HTML，BeautifulSoup使用简介</title><link>https://blog.cndenis.com/Python/2012/12/%E7%94%A8Python%E8%A7%A3%E6%9E%90HTMLBeautifulSoup%E4%BD%BF%E7%94%A8%E7%AE%80%E4%BB%8B.html</link><pubDate>Wed, 12 Dec 2012 00:00:00 +0000</pubDate><guid>https://blog.cndenis.com/Python/2012/12/%E7%94%A8Python%E8%A7%A3%E6%9E%90HTMLBeautifulSoup%E4%BD%BF%E7%94%A8%E7%AE%80%E4%BB%8B.html</guid><description>&lt;p&gt;Beautiful Soup是一个用于解析HTML文件的Python库，这里介绍一下它的基本使用方法。&lt;/p&gt;
&lt;p&gt;Beautiful Soup字面意思是美好的汤，主页在 &lt;a class="link" href="http://www.crummy.com/software/BeautifulSoup/" target="_blank" rel="noopener"
 &gt;http://www.crummy.com/software/BeautifulSoup/&lt;/a&gt;，
下载与安装无需啰嗦，假设你已经装好了，现在开始吧。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;##装汤——Making the Soup&lt;/p&gt;
&lt;p&gt;首先要把待解析的HTML装入BeautifulSoup。BeautifulSoup可以接受文件句柄或是字符串作为输入：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;bs4&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BeautifulSoup&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;fp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;index.html&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;soup1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BeautifulSoup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;soup2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BeautifulSoup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&amp;lt;html&amp;gt;data&amp;lt;/html&amp;gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;p&gt;##汤料——Soup中的对象&lt;/p&gt;
&lt;h3 id="标签tag"&gt;标签（Tag）
&lt;/h3&gt;&lt;p&gt;标签对应于HTML元素，也就是应于一对HTML标签以及括起来的内容（包括内层标签和文本），如：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;soup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BeautifulSoup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;lt;b class=&amp;#34;boldest&amp;#34;&amp;gt;Extremely bold&amp;lt;/b&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;tag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;soup&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;soup.b就是一个标签，soup其实也可以视为是一个标签，其实整个HTML就是由一层套一层的标签组成的。&lt;/p&gt;
&lt;h3 id="名字name"&gt;名字（Name）
&lt;/h3&gt;&lt;p&gt;名字对应于HTML标签中的名字（也就是尖括号里的第一项）。每个标签都具有名字，标签的名字使用&lt;code&gt;.name&lt;/code&gt;来访问，例如上例中，&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sa"&gt;u&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;b&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;soup&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sa"&gt;u&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;[document]&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="属性atrriutes"&gt;属性（Atrriutes）
&lt;/h3&gt;&lt;p&gt;属性对应于HTML标签中的属性部分（也就是尖括号里带等号的那些）。标签可以有许多属性，也可以没有属性。属性使用类似于字典的形式访问，用方括号加属性名，例如上例中，&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;class&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sa"&gt;u&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;boldest&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;可以使用.attrs直接获得这个字典，例如，&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attrs&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sa"&gt;u&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;class&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;u&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;boldest&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="文本text"&gt;文本（Text）
&lt;/h3&gt;&lt;p&gt;文本对应于HTML中的文本（也就是尖括号外的部分）。文件使用&lt;code&gt;.text&lt;/code&gt;来访问，例如上例中，&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sa"&gt;u&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Extremely bold&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;p&gt;##找汤料——Soup中的查找&lt;/p&gt;
&lt;p&gt;解析一个HTML通常是为了找到感兴趣的部分，并提取出来。BeautifulSoup提供了&lt;code&gt;find&lt;/code&gt;和&lt;code&gt;find_all&lt;/code&gt;的方法进行查找。&lt;code&gt;find&lt;/code&gt;只返回找到的第一个标签，而&lt;code&gt;find_all&lt;/code&gt;则返回一个列表。因为查找用得很多，所以BeautifulSoup做了一些很方便的简化的使用方式：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find_all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;a&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;#等价于 tag(&amp;#34;a&amp;#34;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;a&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;#等价于 tag.a&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;因为找不到的话，find_all返回空列表，&lt;code&gt;find&lt;/code&gt;返回&lt;code&gt;None&lt;/code&gt;，而不会抛出异常，所以，也不用担心 &lt;code&gt;tag(&amp;quot;a&amp;quot;)&lt;/code&gt; 或 &lt;code&gt;tag.a&lt;/code&gt; 会因为找不到而报错。限于python的语法对变量名的规定，&lt;code&gt;tag.a&lt;/code&gt; 的形式只能是按名字查找，因为点号.后面只能接变量名，而带括号的形式 &lt;code&gt;tag()&lt;/code&gt; 或 &lt;code&gt;tag.find()&lt;/code&gt; 则可用于以下的各种查找方式。&lt;/p&gt;
&lt;p&gt;查找可以使用多种方式：字符串、列表、键-值（字典）、正则表达式、函数&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;字符串： 字符串会匹配标签的名字，例如 &lt;code&gt;tag.a&lt;/code&gt; 或 &lt;code&gt;tag(&amp;quot;a&amp;quot;)&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;列表： 可以按一个字符串列表查找，返回名字匹配&lt;em&gt;任意&lt;/em&gt;一个字符串的标签。例如 &lt;code&gt;tag(&amp;quot;h2&amp;quot;, &amp;quot;p&amp;quot;)&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;键-值： 可以用&lt;code&gt;tag(key=value)&lt;/code&gt;的形式，来按标签的属性查找。键-值查找里有比较多的小花招，这里列几条：&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;class
&lt;code&gt;class&lt;/code&gt;是Python的保留字，不能当变量名用，偏偏在HTML中会有很多 &lt;code&gt;class=XXX&lt;/code&gt; 的情况，BeautifulSoup的解决方法是加一下划线，用 &lt;code&gt;class_&lt;/code&gt; 代替,如 &lt;code&gt;tag(class_=XXX)&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;True
当值为True时，会匹配所有带这个键的标签，如 &lt;code&gt;tag(href=True)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;text
text做为键时表示查找按标签中的文本查找，如 &lt;code&gt;tag(text=something）&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;正则表达式： 例如 &lt;code&gt;tag(href=re.compile(&amp;quot;elsie&amp;quot;))&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;函数： 当以上方法都行不通时，函数是终极方法。写一个以单个标签为参数的函数，传入 &lt;code&gt;find&lt;/code&gt; 或 &lt;code&gt;find_all&lt;/code&gt; 进行查找。如&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fun&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;has_key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;class&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;has_key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fun&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# 会返回所有带class属性但不带id属性的标签&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;p&gt;##再来一碗——按文档的结构查找&lt;/p&gt;
&lt;p&gt;HTML可以解析成一棵标签树，因此也可以按标签在树中的相互关系来查找。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;查找上层节点：&lt;code&gt;find_parents()&lt;/code&gt; 和 &lt;code&gt;find_parent()&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;查找下一个兄弟节点：&lt;code&gt;find_next_siblings()&lt;/code&gt; 和 &lt;code&gt;find_next_sibling()&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;查找上一个兄弟节点：&lt;code&gt;find_previous_siblings()&lt;/code&gt; 和 &lt;code&gt;find_previous_sibling()&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以上四个都只会查同一父节点下的兄弟&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;查找下层节点：其实上面说的find和find_all就是干这活的&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;查找下一个节点（无视父子兄弟关系） &lt;code&gt;find_all_next()&lt;/code&gt; 和 &lt;code&gt;find_next()&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;查找上一个节点（无视父子兄弟关系） &lt;code&gt;find_all_previous()&lt;/code&gt; 和 &lt;code&gt;find_previous()&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以上的这些查找的参都和&lt;code&gt;find&lt;/code&gt;一样，可以搭配着用。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;##看颜色选汤——按CSS查找&lt;/p&gt;
&lt;p&gt;用 &lt;code&gt;.select()&lt;/code&gt;方法，看 &lt;a class="link" href="http://www.crummy.com/software/BeautifulSoup/bs4/doc/#css-selectors" target="_blank" rel="noopener"
 &gt;http://www.crummy.com/software/BeautifulSoup/bs4/doc/#css-selectors&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;##一些小花招&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;BeautifulSoup 可以支持多种解析器，如lxml, html5lib, html.parser. 如：&lt;code&gt;BeautifulSoup(&amp;quot;&amp;lt;a&amp;gt;&amp;lt;/b&amp;gt;&amp;quot;, &amp;quot;html.parser&amp;quot;)&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;BeautifulSoup 用于解析xml的话，目前只支持lxml，需要自己另行安装。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;具体表现可参考 &lt;a class="link" href="http://www.crummy.com/software/BeautifulSoup/bs4/doc/#differences-between-parsers" target="_blank" rel="noopener"
 &gt;http://www.crummy.com/software/BeautifulSoup/bs4/doc/#differences-between-parsers&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;BeautifulSoup 在解析之前会先把文本转换成unicode。BeautifulSoup会优先考虑使用页面的charset定义。如果遇上网页的charset定义与实际使用的不符，就可能会产年乱码。可以用 &lt;code&gt;from_encoding&lt;/code&gt; 指定编码，如：&lt;code&gt; BeautifulSoup(markup, from_encoding=&amp;quot;gb18030&amp;quot;)&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;soup.prettify()可以输出排列得很好看的HTML文本，遇上中文的话可以指定编码使其显示正常，如 &lt;code&gt;soup.prettify(&amp;quot;gbk&amp;quot;)&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;</description></item></channel></rss>