.. include:: ../include/substitution.rst .. highlight:: erlang :linenothreshold: 3 ************** 第2ç« ä¸²è¡Œç¼–ç¨‹ ************** :翻译: 连城 æœ¬ç« ä»‹ç»ç”¨äºŽç¼–写串行Erlang程åºçš„概念。我们首先讨论å˜é‡èµ‹å€¼çš„基本机制和如何实现控制æµç¨‹ã€‚为æ¤ï¼Œæˆ‘们è¦å…ˆäº†è§£ä¸€ä¸‹\ **项å¼**\ ã€\ **模å¼**\ å’Œ\ **模å¼åŒ¹é…**\ 。 é¡¹å¼ ==== Erlangä¸ä»¥ä¸‹æ•°æ®ç±»åž‹\ [#]_\ 被称为\ **项å¼**\ : - **常é‡**\ 类型 - 数值 - 整数,用于å˜å‚¨è‡ªç„¶æ•° - 浮点数,用于å˜å‚¨å®žæ•° - 原åå¼ - Pidï¼ˆè¿›ç¨‹æ ‡è¯†ç¬¦process identifier的缩写),用于å˜å‚¨è¿›ç¨‹æ ‡è¯† - 引用,用于å˜å‚¨ç³»ç»ŸèŒƒå›´å†…唯一的引用 - **å¤åˆ**\ æ•°æ®ç±»åž‹ - 元组,用于å˜å‚¨å›ºå®šæ•°ç›®çš„å¤šä¸ªé¡¹å¼ - 列表,用于å˜å‚¨å¯å˜æ•°ç›®çš„å¤šä¸ªé¡¹å¼ æ•°å€¼ ---- 以下实例都属于数值: .. code-block:: erlang 123 -34567 12.345 -27.45e-05 整数精度与实现相关,但任何Erlang系统都应ä¿è¯è‡³å°‘24ä½çš„整数精度。 ``$<Char>``\ æ ‡è®°è¡¨ç¤ºå—符\ ``Char``\ 对应的ASCII值,如\ ``$A``\ 表示整数65。 ä¸ä»¥10为基数的整数å¯å†™ä½œ\ ``<Base>#<Value>``\ ,如16#ffff表示å进制整数65535。\ ``Base``\ çš„å–值范围为2 .. 16。 æµ®ç‚¹æ•°ä»¥ä¼ ç»Ÿæ–¹å¼ä¹¦å†™ã€‚ 原åå¼ ------ 原åå¼æ˜¯æœ‰å称的常é‡ã€‚例如在æŸä¸ªç”¨äºŽæ—¥åŽ†è®¡ç®—的程åºä¸å¯ä½¿ç”¨\ ``monday``\ ã€\ ``tuesday``\ ç‰ç‰è¡¨ç¤ºä¸€æ˜ŸæœŸä¸çš„å„天。原åå¼ç”¨äºŽå¢žå¼ºç¨‹åºçš„å¯è¯»æ€§ã€‚ 一些原åå¼å®žä¾‹ï¼š .. code-block:: erlang friday unquoted_atoms_cannot_contain_blanks 'A quoted atom which contains several blanks' 'hello \n my friend' 原åå¼ä»¥å°å†™å—æ¯ï¼ˆ\ ``a..z``\ )开头,以éžå—æ¯æ•°å—å—符结尾——å¦åˆ™å°±å¿…须用引å·æ‹¬èµ·æ¥ã€‚ 通过将原åå¼ä»¥å¼•å·æ‹¬èµ·æ¥ï¼ŒåŽŸåå¼ä¸ä¾¿å¯ä»¥å‡ºçŽ°ä»»æ„å—符。原åå¼æ€»æ˜¯ä»¥å¯è¢« Erlang 读å–程åºè¯»å…¥çš„æ ¼å¼è¾“出。原åå¼å¼•å·å†…çš„å—符éµå¾ªå¦‚下规范: .. csv-table:: :header: å—符, å«ä¹‰ :widths: 25, 75 ``\b`` , é€€æ ¼ç¬¦ ``\d`` , åˆ é™¤ç¬¦ ``\e`` , 转义符(ESC) ``\f`` , æ¢é¡µç¬¦ ``\n`` , æ¢è¡Œç¬¦ ``\r`` , 回车符 ``\t`` , 制表符 ``\v`` , 垂直制表符 ``\\`` , å斜线 ``\^A .. \^Z``\ ,control A到control Z(å³0 .. 26) ``\'`` , å•å¼•å· ``\"`` , åŒå¼•å· ``\OOO`` , ä½¿ç”¨å…«è¿›åˆ¶æ ¼å¼\ ``OOO``\ 表示的å—符 在引å·æ‹¬èµ·æ¥çš„原åå¼ä¸å¦‚果包å«å—符åºåˆ—\ ``\C``\ ,其ä¸\ ``C``\ çš„ASCII值å°äºŽ32,则表示\ ``\C``\ 的这部分æºç è¢«å¿½ç•¥ï¼ˆè¿™æ ·æˆ‘ä»¬åœ¨ç¼–ç¨‹æ—¶å°±å¯ä»¥ä½¿ç”¨ä¸€ä¸ªåæ–œçº¿åŠ æ¢è¡Œç¬¦æ¥å°†é•¿åŽŸåå¼åˆ†éš”ä¸ºå‡ è¡Œï¼‰ã€‚ 元组 ---- 以花括å·åŒ…围的一系列以逗å·åˆ†éš”的项å¼ç§°ä¸º\ **元组**\ 。元组用于å˜å‚¨å›ºå®šæ•°ç›®ä¸ªé¡¹å¼ã€‚å®ƒä»¬ä¸Žä¼ ç»Ÿç¼–ç¨‹è¯è¨€ä¸çš„\ **结构**\ 或\ **记录**\ 类似。 元组\ ``{E1,E2,...,En}``\ ,其ä¸\ ``n``\ 大于0,称为\ **大å°**\ 为\ ``n``\ 的元组。元组ä¸çš„å•ä¸ªé¡¹å¼ç§°ä¸º\ **å…ƒç´ **\ 。 以下是一些元组实例: .. code-block:: erlang {a, 12, 'hello'} {1, 2, {3, 4}, {a, {b, c}}} {} 列表 ---- 以方括å·åŒ…围的一系列以逗å·åˆ†éš”的项å¼æˆä¸º\ **列表**\ 。列表用于å˜å‚¨å¯å˜æ•°ç›®ä¸ªé¡¹å¼ã€‚ 对于列表\ ``[E1,E2,...En]``\ ,其ä¸\ ``n`` >= 0 ,称其长度为\ ``n``\ 。 以下是一些元组实例: .. code-block:: erlang [1, abc, [12], 'foo bar'] [] [a,b,c] "abcd" 被我们称之为å—符串的\ ``"..."``\ æ ‡è®°ï¼Œå®žé™…ä¸Šæ˜¯å¼•å·ä¸å„个å—符组æˆçš„列表的ASCII简写形å¼ã€‚å› æ¤\ ``"abc"``\ 对应于\ ``[97,98,99]``\ 。在原åå¼ä¸ä½¿ç”¨çš„转义规则在å—符串ä¸é€šç”¨ã€‚ 在对列表进行处ç†æ—¶ï¼Œå¾€å¾€éœ€è¦ä¸€ç§æ–¹ä¾¿çš„手段æ¥å¼•ç”¨åˆ—è¡¨çš„ç¬¬ä¸€ä¸ªå…ƒç´ ä»¥åŠé™¤æŽ‰ç¬¬ä¸€ä¸ªå…ƒç´ 以外列表的剩余部分。方便起è§ï¼Œæˆ‘ä»¬å°†åˆ—è¡¨çš„ç¬¬ä¸€ä¸ªå…ƒç´ ç§°ä¸º\ **头部**\ ,将剩余部分称为 *尾部* 。 我们使用\ ``[E1,E2,E3,...,En|Variable]``\ æ¥æ ‡è®°ä¸€ä¸ªå‰\ ``n``\ ä¸ªå…ƒç´ åˆ†åˆ«ä¸º\ ``E1,E2,E3,...,En``\ 而剩余部分记为\ ``Variable``\ 的列表。 注æ„“\ ``|``\ â€ä¹‹åŽçš„项å¼ä¸ä¸€å®šè¦æ˜¯åˆ—表,它å¯ä»¥æ˜¯ä»»æ„一个åˆæ³•çš„Erlang项å¼ã€‚最åŽä¸€ä¸ªå°¾éƒ¨ä¸ºé¡¹å¼\ ``[]``\ 的列表称为\ **真**\ 列表或\ **æ ¼å¼è‰¯å¥½**\ 的列表——大多数(尽管ä¸æ˜¯å…¨éƒ¨ï¼‰Erlang程åºéƒ½æ˜¯è¢«ç¼–写æ¥å¤„ç†æ ¼å¼è‰¯å¥½çš„列表的。 模å¼åŒ¹é… ======== 模å¼ä¸Žé¡¹å¼æœ‰ç€ç›¸åŒçš„结构,但它们还å¯ä»¥åŒ…å«å˜é‡ã€‚å˜é‡å都以大写å—æ¯å¼€å¤´ã€‚ 模å¼ç¤ºä¾‹ï¼š .. code-block:: erlang {A, a, 12, [12,34|{a}]} {A, B, 23} {x, {X_1}, 12, My_cats_age} [] 以上的\ ``A``\ ã€\ ``B``\ ã€\ ``X_1``\ å’Œ\ ``My_cats_age``\ 都是å˜é‡ã€‚ 模å¼åŒ¹é…为å˜é‡èµ‹å€¼æ供了基本的机制。被赋值åŽï¼Œå˜é‡ä¾¿\ **被绑定**\ ——å¦åˆ™ä¾¿æ˜¯\ **未绑定**\ å˜é‡ã€‚ç»™å˜é‡èµ‹å€¼çš„动作称作“绑定â€ã€‚å˜é‡ä¸€æ—¦è¢«ç»‘定便ä¸å¯æ›´æ”¹ã€‚è¿™ç§å˜é‡å±žæ€§è¢«ç§°ä¸º\ **一次性绑定**\ 或\ **å•æ¬¡èµ‹å€¼**\ 。这ç§å±žæ€§ä¸Žä¼ 统命令å¼è¯è¨€çš„\ **ç ´å性赋值**\ [#]_\ 相å。 如果一个\ **模å¼**\ 与一个\ **项å¼**\ 在结构上åŒæž„,且在模å¼ä¸ä»»ä¸€ä½ç½®å‡ºçŽ°çš„原åæ•°æ®ç±»åž‹ä¹Ÿéƒ½åœ¨é¡¹å¼çš„相应ä½ç½®ä¸Šå‡ºçŽ°ï¼Œåˆ™ç§°ä»–们它们相互\ **匹é…**\ 。如果模å¼ä¸åŒ…å«æœªç»‘定å˜é‡ï¼Œåˆ™è¯¥å˜é‡åœ¨åŒ¹é…过程ä¸å°†è¢«ç»‘定到项å¼ä¸ç›¸åº”çš„å…ƒç´ ã€‚å¦‚æžœåœ¨æ¨¡å¼ä¸\ **相åŒçš„**\ å˜é‡å¤šæ¬¡å‡ºçŽ°ï¼Œåˆ™é¡¹å¼ä¸å¯¹åº”ä½ç½®çš„å…ƒç´ ä¹Ÿå¿…é¡»ç›¸åŒã€‚ 模å¼åŒ¹é…在以下情况下å‘生: - 计算形如\ ``Lhs = Rhs``\ 的表达å¼æ—¶ - 调用函数时 - 在\ ``case``\ å’Œ\ ``receive``\ 原è¯ä¸å¯¹æŒ‡å®šæ¨¡å¼è¿›è¡ŒåŒ¹é…æ—¶ ``Pattern = Expression`` ------------------------ 表达å¼\ ``Pattern = Expression``\ 将致使\ ``Expression``\ 被求值,并将其结果与\ ``Pattern``\ 进行匹é…。匹é…è¦ä¹ˆæˆåŠŸè¦ä¹ˆå¤±è´¥ã€‚若匹é…æˆåŠŸåˆ™\ ``Pattern``\ ä¸çš„所有(未绑定)å˜é‡éƒ½å°†è¢«ç»‘定。 以下我们将å‡è®¾æ¨¡å¼åŒ¹é…总是\ **æˆåŠŸ**\ 。对\ **失败**\ 的处ç†å°†åœ¨ç¬¬??ç« è¯¦ç»†è®¨è®ºã€‚ 示例: .. code-block:: erlang {A, B} = {12, apple} 匹é…æˆåŠŸåŽå»ºç«‹ç»‘定关系\ ``A``\ |->|\ ``12``\ [#]_\ å’Œ\ ``B``\ |->|\ ``apple``\ 。 .. code-block:: erlang {C, [Head|Tail]} = {{222, man}, [a,b,c]} 匹é…æˆåŠŸåŽå»ºç«‹ç»‘定关系\ ``C``\ |->|\ ``{222, man}``\ ã€\ ``Head``\ |->|\ ``a``\ å’Œ\ ``Tail``\ |->|\ ``[b, c]``\ 。 .. code-block:: erlang [{person, Name, Age, _}|T] = [{person, fred, 22, male}, {person, susan, 19, female}, ...] 匹é…æˆåŠŸåŽå»ºç«‹ç»‘定关系\ ``T``\ |->|\ ``[{person, susan, 19, female}, ...]}``\ ã€\ ``Name``\ |->|\ ``fred``\ å’Œ\ ``Age``\ |->|\ ``22``\ 。在最åŽä¸€ä¸ªä¾‹åä¸æˆ‘们利用了写作“\ ``_``\ â€çš„\ **匿å**\ å˜é‡â€”—在è¯æ³•ä¸Šéœ€è¦ä¸€ä¸ªå˜é‡å‡ºçŽ°ï¼Œä½†æˆ‘们åˆä¸å…³å¿ƒè¯¥å˜é‡çš„值的时候便å¯ä»¥ä½¿ç”¨åŒ¿åå˜é‡ã€‚ 当一个å˜é‡åœ¨ä¸€ä¸ªæ¨¡å¼ä¸å¤šæ¬¡å‡ºçŽ°æ—¶ï¼Œåªæœ‰è¢«åŒ¹é…çš„å¯¹åº”å…ƒç´ çš„å€¼éƒ½ç›¸åŒæ—¶åŒ¹é…æ‰ä¼šæˆåŠŸã€‚å› æ¤ï¼Œä¸¾ä¾‹æ¥è¯´ï¼Œ\ ``{A, foo, A} = {123, foo, 123}``\ å°†æˆåŠŸåŒ¹é…,并将\ ``A``\ 绑定到\ ``123``\ ,然而\ ``{A, foo, A} = {123, foo, abc}``\ å°±ä¼šå¤±è´¥ï¼Œå› ä¸ºæˆ‘ä»¬ä¸èƒ½å°†\ ``A``\ åŒæ—¶ç»‘定到\ ``123``\ **å’Œ**\ ``abc``\ 。 “\ ``=``\ â€æ˜¯ä¸€ä¸ªå³ç»“åˆçš„ä¸ç¼€è¿ç®—ç¬¦ã€‚å› æ¤\ ``A = B = C = D``\ 将被解æžä¸º\ ``A = (B = (C = D))``\ 。这ç§ç”¨æ³•å¯èƒ½åªæœ‰åœ¨\ ``{A, B} = X = ...``\ è¿™æ ·çš„æž„é€ ä¸æ‰æœ‰ç”¨ï¼Œè¿™æ—¶æˆ‘们å¯ä»¥åŒæ—¶èŽ·æ‚‰è¡¨è¾¾å¼çš„值åŠå…¶ç»„æˆéƒ¨åˆ†ã€‚表达å¼\ ``Lhs = Rhs``\ 的值被定义为\ ``Rhs``\ 。 函数调用ä¸çš„模å¼åŒ¹é… -------------------- Erlang通过模å¼åŒ¹é…æ¥æ供选择和控制æµç¨‹ã€‚例如,程åº2.1定义了一个函数\ ``classify_day/1``\ ,当调用å‚数为\ ``saturday``\ 或\ ``sunday``\ 时返回\ ``weekEnd``\ ,å¦åˆ™è¿”回\ ``weekDay`` 。 .. topic:: ç¨‹åº 2.1 .. code-block:: erlang -module(dates). -export([classify_day/1]). classify_day(saturday) -> weekEnd; classify_day(sunday) -> weekEnd; classify_day(_) -> weekDay. 进行函数求值时,会将函数的å‚数与函数定义ä¸å‡ºçŽ°çš„模å¼ä¸€ä¸€è¿›è¡ŒåŒ¹é…。一旦å‘现一个æˆåŠŸçš„匹é…,“\ ``->``\ â€ä¹‹åŽçš„符å·ä¾¿è¢«æ±‚å€¼ï¼Œå› æ¤ï¼š .. code-block:: erlang > dates:classify_day(saturday). weekEnd > dates:classify_day(friday). weekDay 如果所有的åå¥éƒ½ä¸åŒ¹é…,则函数调用\ **失败**\ (失败将引å‘第??ç« æ述的错误æ•æ‰æœºåˆ¶ï¼‰ã€‚ 当执行æµç¨‹è¿›å…¥ä¸€ä¸ªå‡½æ•°çš„æŸä¸ªåå¥æ—¶ï¼Œæ述该åå¥çš„模å¼æ‰€åŒ…å«çš„å˜é‡å°†è¢«ç»‘å®šã€‚å› æ¤ï¼Œä¸¾ä¾‹æ¥è¯´ï¼Œå¯¹ç¨‹åº1.3çš„\ ``math3:area({square, 5})``\ 进行求值将致使å˜é‡\ ``Side``\ 被绑定到\ ``5``\ 。 表达å¼æ±‚值 ========== 表达å¼å…·å¤‡ä¸Žæ¨¡å¼ç›¸åŒçš„è¯æ³•ï¼ŒåŒæ—¶è¡¨è¾¾å¼è¿˜å¯ä»¥åŒ…å«å‡½æ•°è°ƒç”¨æˆ–ä¼ ç»Ÿçš„ä¸åºç®—术表达å¼ã€‚å‡½æ•°è°ƒç”¨çš„å†™æ³•å¾ˆä¼ ç»Ÿï¼Œå¦‚ï¼š\ ``area:triangle(A, B, C)``\ 便代表以å‚æ•°\ ``A``\ ã€\ ``B``\ å’Œ\ ``C``\ 调用函数\ ``area:triangle``\ 。 Erlang 表达å¼çš„求值机制如下。 对项å¼æ±‚值得到其本身: .. code-block:: erlang > 222. 222 > abc. abc > 3.1415926. 3.14159 > {a,12,[b,c|d]}. {a,12,[b,c|d]} > {{},[{}],{a,45,'hello world'}}. {{},[{}],{a,45,'hello world'}} æµ®ç‚¹æ•°çš„è¾“å‡ºæ ¼å¼å¯èƒ½ä¸Žå®ƒä»¬çš„è¾“å…¥æ ¼å¼ä¸å®Œå…¨ä¸€è‡´ã€‚当表达å¼ä¸Žé¡¹å¼åŒæž„且表达å¼ä¸çš„函数调用都已求值完毕时,表达å¼å°†è¢«æ±‚值为项å¼ã€‚应用一个函数时其å‚数首先被求值。 求值过程å¯ä»¥è¢«è®¤ä¸ºæ˜¯ä¸€ä¸ªå°†è¡¨è¾¾å¼å½’结为基础项å¼çš„函数: .. parsed-literal:: |eps|\ (X) when Constant(X)\ |-->|\ X |eps|\ ({t1,t2,...,tn})\ |-->|\ {\ |eps|\ (t1),\ |eps|\ (t2),...,\ |eps|\ (tn)} |eps|\ ([t1,t2,...,tn])\ |-->|\ [\ |eps|\ (t1),\ |eps|\ (t2),...,\ |eps|\ (tn)] |eps|\ (functionName(t1,t2,...,tn)\ |-->| APPLY(functionName,[\ |eps|\ (t1),\ |eps|\ (t2),...,\ |eps|\ (tn)]) å…¶ä¸\ ``APPLY``\ 表示一个将å‚数应用到函数的函数。 函数求值 -------- 函数调用的写法如以下实例所示: .. code-block:: erlang > length([a,b,c]). 3 > lists:append([a,b], [1,2,3]). [a,b,1,2,3] > math:pi(). 3.14159 带冒å·å½¢å¼çš„函数将在和模å—ç›¸å…³çš„ç« èŠ‚ä¸è§£é‡Šã€‚调用没有å‚æ•°çš„å‡½æ•°å¿…é¡»åŠ ä¸Šä¸€å¯¹ç©ºçš„å°æ‹¬å·ï¼ˆä»¥æ¤ä¸ŽåŽŸåå¼ç›¸åŒºåˆ«ï¼‰ã€‚ æ±‚å€¼é¡ºåº -------- 函数å‚数的求值顺åºæ˜¯ä¸ç¡®å®šçš„。例如,\ ``f({a},b(),g(a,h(b),{f,X}))``\ 表示一个函数调用。对函数\ ``f``\ 的调用有三个å‚数:\ ``{a}``\ ã€\ ``b()``\ å’Œ\ ``g(a,h(b),{f,X})``\ 。第一个å‚数是一个åªåŒ…å«ä¸€ä¸ªåŽŸå项\ ``a``\ 的元组。第二个å‚数是一个函数调用\ ``b()``\ 。第三个å‚数是函数调用\ ``g(a,h(b),{f,X})``\ 。在对\ ``f/3``\ 求值时,对\ ``b/0``\ å’Œ\ ``g/3``\ 的求值顺åºæ˜¯ä¸ç¡®å®šçš„,ä¸è¿‡\ ``h(b)``\ 在\ ``g/3``\ 被求值。对\ ``b()``\ å’Œ\ ``h(b)``\ 的求值顺åºä¹Ÿæ˜¯ä¸ç¡®å®šçš„。 在对形如\ ``[f(a), g(b), h(k)]``\ 的表达å¼è¿›è¡Œæ±‚值时,\ ``f(a)``\ ã€\ ``g(b)``\ å’Œ\ ``h(k)``\ 的求值顺åºæ˜¯ä¸ç¡®å®šçš„。 如果\ ``f(a)``\ ã€\ ``g(b)``\ å’Œ\ ``h(k)``\ 的求值过程没有副作用(å³ä¸å‘é€æ¶ˆæ¯ã€ä¸åˆ›å»ºè¿›ç¨‹ç‰ç‰ï¼‰ï¼Œåˆ™\ ``[f(a), g(b), h(k)]``\ çš„\ **值**\ 与求值顺åºæ— å…³\ [#]_\ 。这ç§å±žæ€§å«ä½œ\ **引用é€æ˜Žæ€§**\ [#]_\ 。 应用 ---- BIF ``apply(Mod, Func, ArgList)``\ å’Œ\ ``apply({Mod, Func}, ArgList)``\ 用于将模å—\ ``Mod``\ ä¸çš„函数\ ``Func``\ 应用到å‚数列表\ ``ArgList``\ 。 .. code-block:: erlang > apply(dates, classify_day, [monday]). weekDay > apply(math, sqrt, [4]). 2.0 > apply({erlang, atom_to_list}, [abc]). [97,98,99] 使用\ ``apply``\ 对BIF进行求值时,å¯ä»¥ä½¿ç”¨\ ``erlang``\ 作为模å—å。 模å—系统 ======== Erlang具备一套模å—系统以便我们将大型程åºåˆ‡åˆ†ä¸ºä¸€ç»„模å—。æ¯ä¸ªæ¨¡å—都有自己的åç§°ç©ºé—´ï¼›è¿™æ ·æˆ‘ä»¬å°±å¯ä»¥åœ¨ä¸åŒçš„模å—ä¸è‡ªç”±åœ°ä½¿ç”¨ç›¸åŒçš„函数å而ä¸ä¼šæœ‰ä»»ä½•å†²çªã€‚ 模å—系统以对给定模å—ä¸å‡½æ•°çš„å¯è§æ€§è¿›è¡Œé™åˆ¶çš„æ–¹å¼æ¥å·¥ä½œçš„。函数的调用方å¼å–决于模å—åã€å‡½æ•°å以åŠå‡½æ•°å是å¦åœ¨æ¨¡å—的导入或导出声明ä¸å‡ºçŽ°ã€‚ .. topic:: ç¨‹åº 2.2 .. code-block:: erlang -module(lists1). -export([reverse/1]). reverse(L) -> reverse(L, []). reverse([H|T], L) -> reverse(T, [H|L]); reverse([], L) -> L. 程åº2.2å®šä¹‰äº†ä¸€ä¸ªé¢ å€’åˆ—è¡¨å…ƒç´ é¡ºåºçš„函数\ ``reverse/1``\ 。\ ``reverse/1``\ 是该模å—ä¸\ **唯一**\ å¯ä»¥ä»Žè¯¥æ¨¡å—之外被调用的函数。需è¦ä»Žæ¨¡å—外部调用的函数必须出现在模å—的导出声明ä¸ã€‚ 该模å—ä¸å®šä¹‰çš„其他函数,\ ``reverse/2``\ ,仅å¯ä¾›æ¨¡å—\ **内部**\ 使用。注æ„\ ``reverse/1``\ å’Œ\ ``reverse/2``\ 是完全ä¸åŒçš„函数。在Erlangä¸ï¼Œåå—相åŒä½†å‚æ•°æ•°ç›®ä¸åŒçš„两个函数是完全ä¸åŒçš„函数。 模å—间调用 ---------- 从其他模å—ä¸è°ƒç”¨å‡½æ•°çš„方法有两ç§ï¼š .. topic:: ç¨‹åº 2.3 .. code-block:: erlang -module(sort1). -export([reverse_sort/1, sort/1]). reverse_sort(L) -> lists1:reverse(sort(L)). sort(L) -> lists:sort(L). ``reverse/1``\ 以\ **完全é™å®šå称**\ 被调用。 ä½ è¿˜å¯ä»¥å€ŸåŠ©\ ``import``\ 声明使用\ **éšå¼é™å®šå‡½æ•°å**\ ,如程åº2.4所示。 .. topic:: ç¨‹åº 2.4 .. code-block:: erlang -module(sort2). -import(lists1, [reverse/1]). -export([reverse_sort/1, sort/1]). reverse_sort(L) -> reverse(sort(L)). sort(L) -> lists:sort(L). 两ç§å½¢å¼éƒ½æ˜¯ä¸ºäº†è§£å†³äºŒä¹‰æ€§ã€‚比如,当两个ä¸åŒçš„模å—导出了é‡å的函数,则必须显å¼é™å®šå‡½æ•°å。 函数定义 ======== ä»¥ä¸‹ç« èŠ‚æ›´è¯¦ç»†åœ°æ述了Erlang函数的è¯æ³•ã€‚首先我æ¥ç»™å‡½æ•°çš„å„个è¯æ³•å…ƒç´ 命å。接ç€å°†è¯¦ç»†æè¿°è¿™äº›å…ƒç´ ã€‚ æœ¯è¯ ---- 考虑以下模å—:\ [*]_ .. topic:: ç¨‹åº 2.5 .. code-block:: erlang -module(lists2). -export([flat_length/1]). %% flat_length(List) %% Calculate the length of a list of lists. flat_length(List) -> flat_length(List, 0). flat_length([H|T], N) when list(H) -> flat_length(H, flat_length(T, N)); flat_length([H|T], N) -> flat_length(T, N + 1); flat_length([], N) -> N. 以“\ ``%``\ â€æ‰“头的是注释。注释å¯ä»¥ä»Žä¸€è¡Œçš„ä»»æ„ä½ç½®å¼€å§‹ï¼Œä¸€ç›´æŒç»åˆ°è¡Œæœ«ã€‚ 第1行包å«\ **模å—**\ 声明。该行必须出现在任何其他声明或代ç 之å‰ã€‚ 第1行和第3行开头的“\ ``-``\ â€ç§°ä¸º\ **属性å‰ç¼€**\ 。\ ``module(list2)``\ 便是属性的一个例å。 第2ã€ç¬¬4ç‰è¡Œæ˜¯ç©ºè¡Œâ€”—连ç»çš„å•ä¸ªæˆ–多个空白符ã€ç©ºè¡Œã€åˆ¶è¡¨ç¬¦ã€æ¢è¡Œç¬¦ç‰ï¼Œéƒ½è¢«å½“作å•ä¸ªç©ºç™½ç¬¦å¤„ç†ã€‚ 第3行声明了一个具有一个å‚数的函数\ ``flag_length``\ ,该行æ„味ç€è¯¥å‡½æ•°å˜åœ¨äºŽæ¨¡å—ä¸å¹¶ä¼šè¢«ä»Žæ¨¡å—ä¸å¯¼å‡ºã€‚ 第5ã€6行是注释。 第8ã€9行包å«äº†å‡½æ•°\ ``flat_length/1``\ 的定义。它由å•ä¸ª\ **åå¥**\ 组æˆã€‚ 表达å¼\ ``flat_length(List)``\ 称为åå¥çš„\ **头部**\ 。“\ ``->``\ â€ä¹‹åŽçš„部分为åå¥çš„\ **主体**\ 。 第11至16行函数\ ``flat_length/2``\ 的定义——该函数包å«ä¸‰ä¸ªåå¥ï¼›åå¥é—´ä»¥åˆ†å·â€œ\ ``;``\ â€åˆ†éš”,在最åŽçš„结尾处以“\ ``.``\ â€ç»“尾。 第11è¡Œä¸\ ``flat_length/2``\ 的第一个å‚数为列表\ ``[H|T]``\ 。\ ``H``\ 表示列表的\ **头部**\ ,\ ``T``\ 代表列表的\ **尾部**\ 。在关键å—\ ``when``\ å’Œç®å¤´â€œ\ ``->``\ â€ä¹‹é—´çš„表达å¼\ ``list(H)``\ 称作ä¿æŠ¤å¼ã€‚åªæœ‰åœ¨å‚数与函数头部的模å¼ç›¸åŒ¹é…且ä¿æŠ¤å¼æ–言æˆç«‹æ—¶ï¼Œå‡½æ•°ä½“æ‰ä¼šè¢«æ±‚值。 ``flat_length/2``\ 的第一个åå¥ç§°ä¸º\ **ä¿æŠ¤åå¥**\ ;其他的åå¥ç§°ä¸º\ **æ— ä¿æŠ¤åå¥**\ 。 ``flat_length/2``\ 是一个\ **局部函数**\ ——å³ä¸å¯ä»Žæ¨¡å—å¤–éƒ¨è¢«è°ƒç”¨ï¼ˆå› ä¸ºå®ƒæ²¡æœ‰å‡ºçŽ°åœ¨\ ``export``\ 属性ä¸ï¼‰ã€‚ 模å—\ ``lists2``\ 包å«äº†å‡½æ•°\ ``flat_length/1``\ **å’Œ**\ ``flat_length/2``\ 的定义。它们代表\ **两个完全ä¸åŒçš„函数**\ ——这与C或Pascalç‰è¯è¨€ä¸é€šï¼Œåœ¨è¿™äº›è¯è¨€ä¸ä¸€ä¸ªå‡½æ•°ååªèƒ½å‡ºçŽ°ä¸€æ¬¡ï¼Œä¸”åªèƒ½æœ‰\ **固定**\ 个数的å‚数。 åå¥ ---- æ¯ä¸ªå‡½æ•°éƒ½ç”±ä¸€ç»„\ **åå¥**\ 组æˆã€‚åå¥é—´ä»¥åˆ†å·â€œ\ ``;``\ â€åˆ†éš”。æ¯ä¸ªåå¥éƒ½åŒ…å«ä¸€ä¸ªåå¥å¤´éƒ¨ã€ä¸€ä¸ªå¯é€‰çš„ä¿æŠ¤å¼å’Œåå¥ä¸»ä½“。下é¢å°†è¯¦ç»†è§£é‡Šã€‚ åå¥å¤´éƒ¨ -------- åå¥çš„头部包å«ä¸€ä¸ªå‡½æ•°å和一组以逗å·åˆ†éš”çš„å‚数。æ¯ä¸ªå‚数都是一个åˆæ³•çš„模å¼ã€‚ 当函数调用å‘生时,将会按顺åºå¯¹å‡½æ•°å®šä¹‰ä¸çš„åå¥å¤´éƒ¨ä¾æ¬¡è¿›è¡ŒåŒ¹é…。 åå¥ä¿æŠ¤å¼ ---------- ä¿æŠ¤å¼æ˜¯åå¥è¢«é€‰ä¸å‰å¿…é¡»è¦æ»¡è¶³çš„æ¡ä»¶ã€‚ ä¿æŠ¤å¼å¯ä»¥æ˜¯ä¸€ä¸ªç®€å•çš„æ–言或是一组由逗å·åˆ†éš”的简å•æ–言。一个简å•æ–言å¯ä»¥æ˜¯ä¸€ä¸ªç®—数比较ã€é¡¹å¼æ¯”较,或是一个系统预定义的æ–言函数。ä¿æŠ¤å¼å¯ä»¥çœ‹ä½œæ˜¯æ¨¡å¼åŒ¹é…的一ç§æ‰©å±•ã€‚用户自定义的函数ä¸èƒ½ç”¨åœ¨ä¿æŠ¤å¼å†…。 对ä¿æŠ¤å¼æ±‚值时所有的æ–言都将被求值。若所有æ–言都为真,则ä¿æŠ¤å¼æˆç«‹ï¼Œå¦åˆ™å°±å¤±è´¥ã€‚ä¿æŠ¤å¼ä¸å„个æ–言的求值顺åºæ˜¯ä¸ç¡®å®šçš„。 如果ä¿æŠ¤å¼æˆç«‹ï¼Œåˆ™ä¼šå¯¹åå¥çš„主体进行求值。如果ä¿æŠ¤å¼å¤±è´¥ï¼Œåˆ™å°è¯•ä¸‹ä¸€ä¸ªå€™é€‰åå¥ã€‚ 一旦åå¥çš„头部和ä¿æŠ¤å¼éƒ½åŒ¹é…æˆåŠŸï¼Œç³»ç»Ÿå°†\ **指定**\ è¿™æ¡åå¥å¹¶å¯¹å…¶ä¸»ä½“求值。 我们å¯ä»¥å†™ä¸€ä¸ªä¿æŠ¤å¼ç‰ˆæœ¬çš„\ ``factorial``\ 。 .. code-block:: erlang factorial(N) when N == 0 -> 1; factorial(N) when N > 0 -> N * factorial(N - 1). 注æ„对于以上示例,我们å¯ä»¥è°ƒæ¢åå¥çš„顺åºï¼Œå³ï¼š .. code-block:: erlang factorial(N) when N > 0 -> N * factorial(N - 1); factorial(N) when N == 0 -> 1. 在这个示例ä¸åå¥é¦–部模å¼ä¸Žä¿æŠ¤å¼çš„组åˆå¯ä»¥å”¯ä¸€ç¡®å®šä¸€ä¸ªæ£ç¡®çš„åå¥ã€‚ ä¿æŠ¤å¼æ–言 ---------- ä¿æŠ¤å¼æ–言的完整集åˆå¦‚下: .. csv-table:: :header: ä¿æŠ¤å¼, æˆç«‹æ¡ä»¶ :widths: 40, 60 ``atom(X)``, ``X``\ 是一个原åå¼ ``constant(X)``, ``X``\ ä¸æ˜¯åˆ—表或元组 ``float(X)``, ``X``\ 是一个浮点数 ``integer(X)``, ``X``\ 是一个整数 ``list(X)``, ``X``\ 是一个列表或 ``[]`` ``number``, ``X``\ 是一个整数或浮点数 ``pid(X)``, ``X``\ æ˜¯ä¸€ä¸ªè¿›ç¨‹æ ‡è¯†ç¬¦ ``port(X)``, ``X``\ æ˜¯ä¸€ä¸ªç«¯å£ ``reference(X)``, ``X``\ 是一个引用 ``tuple(X)``, ``X``\ 是一个元组 ``binary(X)``, ``X``\ æ˜¯ä¸€æ®µäºŒè¿›åˆ¶æ•°æ® å¦å¤–,一些BIF和算术表达å¼çš„组åˆä¹Ÿå¯ä»¥ä½œä¸ºä¿æŠ¤å¼ã€‚它们是: .. code-block:: erlang element/2, float/1, hd/1, length/1, round/1, self/0, size/1 trunc/1, tl/1, abs/1, node/1, node/0, nodes/0 项å¼æ¯”较 -------- å¯ä»¥å‡ºçŽ°åœ¨ä¿æŠ¤å¼ä¸çš„项å¼æ¯”较è¿ç®—符如下: .. csv-table:: :header: è¿ç®—符, æè¿°, 类型 :widths: 30, 40, 30 ``X > Y``, ``X``\ 大于\ ``Y``, coerce ``X < Y``, ``X``\ å°äºŽ\ ``Y``, coerce ``X =< Y``, ``X``\ å°äºŽæˆ–ç‰äºŽ\ ``Y``, coerce ``X >= Y``, ``X``\ 大于或ç‰äºŽ\ ``Y``, coerce ``X == Y``, ``X``\ ç‰äºŽ\ ``Y``, coerce ``X /= Y``, ``X``\ ä¸ç‰äºŽ\ ``Y``, coerce ``X =:= Y``, ``X``\ ç‰äºŽ\ ``Y``, exact ``X =/= Y``, ``X``\ ä¸ç‰äºŽ\ ``Y``, exact 比较è¿ç®—符工作机制如下:首先对è¿ç®—符两边求值(如,在表达å¼ä¸¤è¾¹å˜åœ¨ç®—术表达å¼æˆ–包å«BIFä¿æŠ¤å¼å‡½æ•°æ—¶ï¼‰ï¼›ç„¶åŽå†è¿›è¡Œæ¯”较。 为了进行比较,定义如下的ååºå…³ç³»ï¼š .. code-block:: erlang number < atom < reference < port < pid < tuple < list 元组首先按大å°æŽ’åºï¼Œç„¶åŽå†æŒ‰å…ƒç´ 排åºã€‚列表的比较顺åºæ˜¯å…ˆå¤´éƒ¨ï¼ŒåŽå°¾éƒ¨ã€‚ .. 下文coerceå’Œexact待翻译 如果比较è¿ç®—符的两个å‚数都是数值类型且è¿ç®—符为\ *coerce*\ 型,则如果一个å‚数是\ ``integer``\ å¦ä¸€ä¸ªæ˜¯\ ``float``\ ,那么\ ``integer``\ 将被转æ¢ä¸º\ ``float``\ å†è¿›è¡Œæ¯”较。 ``exact``\ 类型的è¿ç®—符则ä¸åšè¿™æ ·çš„转æ¢ã€‚ å› æ¤\ ``5.0 == 1 + 4``\ 为真,而\ ``5.0 =:= 4 + 1``\ 为å‡ã€‚ ä¿æŠ¤å‡½æ•°åå¥ç¤ºä¾‹ï¼š .. code-block:: erlang foo(X, Y, Z) when integer(X), integer(Y), integer(Z), X == Y + Z -> foo(X, Y, Z) when list(X), hd(X) == {Y, length(Z)} -> foo(X, Y, Z) when {X, Y, size(Z)} == {a, 12, X} -> foo(X) when list(X), hd(X) == c1, hd(tl(X)) == c2 -> 注æ„在ä¿æŠ¤å¼ä¸ä¸å¯å¼•å…¥æ–°çš„å˜é‡ã€‚ åå¥ä¸»ä½“ -------- åå¥çš„主体有一个或多个有逗å·åˆ†éš”的表达å¼åºåˆ—组æˆã€‚åºåˆ—ä¸çš„表达å¼ä¾æ¬¡è¢«æ±‚值。表达å¼åºåˆ—的值被定义为åºåˆ—ä¸\ **最åŽä¸€ä¸ª**\ 表达å¼çš„值。例如,\ ``factorial``\ 的第二个åå¥å¯ä»¥å†™æˆï¼š .. code-block:: erlang factorial(N) when N > 0 -> N1 = N - 1, F1 = factorial(N1), N * F1. 在对åºåˆ—求值的过程ä¸ï¼Œè¡¨è¾¾å¼çš„求值结果è¦ä¹ˆä¸Žä¸€ä¸ªæ¨¡å¼è¿›è¡ŒåŒ¹é…,è¦ä¹ˆè¢«ç›´æŽ¥ä¸¢å¼ƒã€‚将函数主体拆分为åºåˆ—çš„åŽŸå› æœ‰è¿™ä¹ˆå‡ æ¡ï¼š - ç¡®ä¿ä»£ç 的顺åºæ‰§è¡Œâ€”—函数主体ä¸çš„表达å¼æ˜¯ä¾æ¬¡æ±‚值的,而在嵌套的函数调用ä¸çš„函数则å¯èƒ½ä»¥ä»»æ„顺åºæ‰§è¡Œã€‚ - 增强代ç å¯è¯»æ€§â€”—将函数写æˆè¡¨è¾¾å¼åºåˆ—å¯ä»¥ä»¤ç¨‹åºæ›´æ¸…晰。 - (通过模å¼åŒ¹é…)拆解函数的返回值。 - é‡ç”¨å‡½æ•°è°ƒç”¨çš„返回值。 对函数返回值的多次é‡ç”¨çš„示例如下: .. code-block:: erlang good(X) -> Temp = lic(X), {cos(Temp), sin(Temp)}. 上é¢çš„写法比下é¢è¿™ä¹ˆå†™è¦å¥½ï¼š .. code-block:: erlang bad(X) -> {cos(lic(X)), sin(lic(X)}. 二者表达的是åŒä¸€ä¸ªå«ä¹‰ã€‚\ ``lic``\ 代表长而å¤æ‚的计算过程(Long and Involved Calculation),å³é‚£äº›è®¡ç®—代价高的函数。 åŽŸè¯ ==== Erlangæ供了元è¯\ ``case``\ å’Œ\ ``if``\ ï¼Œè¿™æ ·åœ¨åå¥ä¸æ— 需借助其他函数便å¯ä»¥ç›´æŽ¥è¿›è¡Œæ¡ä»¶æ±‚值。 Case ---- ``case``\ 表达å¼å…许在åå¥ä¸»ä½“内部于多个选项ä¸è¿›è¡Œé€‰æ‹©ï¼Œè¯æ³•å¦‚下: .. code-block:: erlang case Expr of Pattern1 [when Guard1] -> Seq1; Pattern2 [when Guard2] -> Seq2; ... PatternN [when GuardN] -> SeqN end 首先,对\ ``Expr``\ 求值,然åŽï¼Œ\ ``Expr``\ 的值将ä¾æ¬¡ä¸Žæ¨¡å¼\ ``Pattern1``\ ã€\ ``Pattern2``\ ……\ ``PatternN``\ 进行匹é…,直到匹é…æˆåŠŸã€‚如果找到一个匹é…并且(å¯é€‰çš„)的ä¿æŠ¤å¼æˆç«‹ï¼Œåˆ™å¯¹åº”的调用åºåˆ—将被求值。注æ„\ ``case``\ ä¿æŠ¤å¼ä¸Žå‡½æ•°ä¿æŠ¤å¼å½¢å¼ç›¸åŒã€‚\ ``case``\ 原è¯çš„值就是被选ä¸çš„åºåˆ—的值。 至少得有一个模å¼\ **å¿…é¡»**\ 得以匹é…——å¦åˆ™å°±ä¼šäº§ç”Ÿä¸€ä¸ªè¿è¡Œæ—¶é”™è¯¯å¹¶å¼•å‘第??ç« ä¸çš„错误处ç†æœºåˆ¶ã€‚ 举个例å,比方说我们我有个函数\ ``allocate(Resource)``\ 用于分é…æŸç§èµ„æº\ ``Resource``\ 。å‡è®¾è¿™ä¸ªå‡½æ•°åªè¿”回\ ``{yes, Address}``\ 或\ ``no``\ ã€‚è¿™æ ·ï¼Œè¿™ä¸ªå‡½æ•°ä¾¿å¯ä»¥æ”¾åœ¨ä¸€ä¸ª\ ``case``\ 结构里: .. code-block:: erlang ... case allocate(Resource) of {yes,Address} when Address > 0, Address =< Max -> Sequence 1 ... ; no -> Sequence 2 ... end ... 在\ ``Sequence 1 ...``\ ä¸ï¼Œå˜é‡\ ``Address``\ å·²ç»è¢«ç»‘定在了\ ``allocate/1``\ 的返回结果上。 为了é¿å…匹é…错误的å‘ç”Ÿï¼Œæˆ‘ä»¬å¸¸å¸¸è¿½åŠ ä¸€ä¸ªå¿…ä¼šåŒ¹é…的模å¼\ [#]_\ 作为\ ``case``\ 原è¯çš„最åŽä¸€ä¸ªåˆ†æ”¯ï¼š .. code-block:: erlang case Fn of ... _ -> true end If -- ``if``\ 表达å¼çš„è¯æ³•å¦‚下: .. code-block:: erlang if Guard1 -> Sequence1 ; Guard2 -> Sequence2 ; ... end 在这ç§æƒ…况下,ä¿æŠ¤å¼\ ``Guard1,...``\ 将被ä¾æ¬¡æ±‚值。如果一个ä¿æŠ¤å¼æˆç«‹åˆ™å¯¹ä¸Žä¹‹å…³è”çš„åºåˆ—求值。该åºåˆ—的求值结果便是\ ``if``\ 结构的结果。\ ``if``\ ä¿æŠ¤å¼ä¸Žå‡½æ•°ä¿æŠ¤å¼å½¢å¼ç›¸åŒã€‚与\ ``case``\ 相åŒï¼Œä¸€ä¸ªä¿æŠ¤å¼éƒ½ä¸æˆç«‹çš„è¯å°†å¼•å‘一个错误。如果需è¦ï¼Œå¯ä»¥å¢žåŠ ä¿æŠ¤å¼æ–言\ ``true``\ 作为垃圾箱: .. code-block:: erlang if ... true -> true end Case å’Œ if 使用示例 ------------------- 使用\ ``case``\ å’Œ\ ``if``\ 我们å¯ä»¥ä»¥å¤šç§æ–¹å¼æ¥ç¼–写\ ``factorial``\ 。 最简å•çš„: .. code-block:: erlang factorial(0) -> 1; factorial(N) -> N * factorial(N - 1). 使用函数ä¿æŠ¤å¼ï¼š .. code-block:: erlang factorial(0) -> 1; factorial(N) when N > 0 -> N * factorial(N - 1). 使用\ ``if``\ : .. code-block:: erlang factorial(N) -> if N == 0 -> 1; N > 0 -> N * factorial(N - 1) end. 使用\ ``case``\ : .. code-block:: erlang factorial(N) -> case N of 0 -> 1; N when N > 0 -> N * factorial(N - 1) end. 使用å˜é‡ä¿æŒä¸´æ—¶ç»“果: .. code-block:: erlang factorial(0) -> 1; factorial(N) when N > 0 -> N1 = N - 1, F1 = factorial(N1), N * F1. 以上所有定义都是æ£ç¡®ä¸”ç‰ä»·çš„\ [#]_\ ——如何进行选择完全是个美å¦é—®é¢˜\ [#]_\ 。 ç®—æœ¯è¡¨è¾¾å¼ ========== 算术表达å¼ç”±ä»¥ä¸‹è¿ç®—符构æˆï¼š .. csv-table:: :header: è¿ç®—符, æè¿°, 类型, æ“作数类型, 优先级 :widths: 15, 50, 10, 15, 10 ``+ X``, ``+ X``, å•ç›®, æ··åˆ, 1 ``- X``, ``- X``, å•ç›®, æ··åˆ, 1 ``X * Y``, ``X * Y``, åŒç›®, æ··åˆ, 2 ``X / Y``, ``X / Y``\ (浮点除法), åŒç›®, æ··åˆ, 2 ``X div Y``, ``X``\ 整除\ ``Y``, åŒç›®, æ•´æ•°, 2 ``X rem Y``, ``X``\ 除以\ ``Y``\ 的余数, åŒç›®, æ•´æ•°, 2 ``X band Y``, ``X``\ 与\ ``Y``\ çš„ä½ä¸Ž, åŒç›®, æ•´æ•°, 2 ``X + Y``, ``X + Y``, åŒç›®, æ··åˆ, 3 ``X - Y``, ``X - Y``, åŒç›®, æ··åˆ, 3 ``X bor Y``, ``X``\ 与\ ``Y``\ ä½æˆ–, åŒç›®, æ•´æ•°, 3 ``X bxor Y``, ``X``\ 与\ ``Y``\ çš„ä½ç®—数异或, åŒç›®, æ•´æ•°, 3 ``X bsl N``, ``X``\ 算数左移\ ``N``\ ä½, åŒç›®, æ•´æ•°, 3 ``X bsr N``, ``X``\ å³ç§»\ ``N``\ ä½, åŒç›®, æ•´æ•°, 3 **å•ç›®**\ è¿ç®—符有一个å‚数,\ **åŒç›®**\ è¿ç®—符有两个å‚数。\ **æ··åˆ**\ æ„味ç€å‚æ•°å³å¯ä»¥æ˜¯\ ``integer``\ 也å¯ä»¥æ˜¯\ ``float``\ 。å•ç›®è¿ç®—符的返回值与其å‚数类型相åŒã€‚ åŒç›®æ··åˆè¿ç®—符(å³\ ``*``\ ã€\ ``-``\ ã€\ ``+``\ )在å‚数都是\ ``integer``\ 时返回类型为\ ``integer``\ 的对象,在å‚数至少包å«ä¸€ä¸ª\ ``float``\ 时返回一个\ ``float``\ 。浮点除法è¿ç®—符\ ``/``\ 总是返回一个\ ``float``\ 。 åŒç›®æ•´æ•°è¿ç®—符(å³\ ``band``\ ã€\ ``div``\ ã€\ ``rem``\ ã€\ ``bor``\ ã€\ ``bxor``\ ã€\ ``bsl``\ ã€\ ``bsr``\ )的å‚数必须是整数,其返回值也是整数。 求值顺åºå–决于è¿ç®—符的优先级:首先计算第1优先级的è¿ç®—符,然åŽæ˜¯ç¬¬2优先级,以æ¤ç±»æŽ¨ã€‚括å·å†…的表达å¼ä¼˜å…ˆæ±‚值。 优先级相åŒçš„è¿ç®—符从左到å³è¿›è¡Œæ±‚值。比如: .. code-block:: erlang A - B - C - D 其求值顺åºä¸Žä¸‹é¢çš„表达å¼ä¸€è‡´ï¼š .. code-block:: erlang (((A - B) - C) - D) å˜é‡ä½œç”¨åŸŸ ========== åå¥ä¸å˜é‡çš„生å˜æœŸä»Žå®ƒé¦–次被绑定处开始,到åå¥ä¸å¯¹è¯¥å˜é‡çš„最åŽä¸€ä¸ªå¼•ç”¨å¤„结æŸã€‚å˜é‡çš„绑定åªä¼šåœ¨æ¨¡å¼åŒ¹é…ä¸å‘生;å¯ä»¥å°†ä¹‹è®¤ä½œæ˜¯ä¸€ä¸ªå˜é‡äº§ç”Ÿè¿‡ç¨‹ã€‚åŽç»å¯¹å˜é‡çš„所有引用都是对å˜é‡çš„值的\ **使用**\ 。\ **表达å¼ä¸çš„å˜é‡å¿…须是ç»è¿‡ç»‘定的**\ 。å˜é‡ç¬¬ä¸€æ¬¡å‡ºçŽ°æ—¶å°±è¢«ç”¨åœ¨è¡¨è¾¾å¼ä¸æ˜¯éžæ³•çš„。比如: .. code-block:: erlang :linenos: f(X) -> Y = g(X), h(Y, X), p(Y). 第1è¡Œä¸ï¼Œå®šä¹‰äº†å˜é‡\ ``X``\ (它在进入函数时被绑定)。第2è¡Œä¸ï¼Œä½¿ç”¨äº†\ ``X``\ ,定义了\ ``Y``\ (首次出现)。第3è¡Œä¸ï¼Œä½¿ç”¨äº†\ ``X``\ å’Œ\ ``Y``\ ,然åŽåœ¨ç¬¬4è¡Œä¸ä½¿ç”¨äº†\ ``Y``\ 。 ``if``\ ã€\ ``case``\ å’Œ\ ``receive``\ 的作用域规则 --------------------------------------------------- 在\ ``if``\ ã€\ ``case``\ 或\ ``receive``\ 原è¯ä¸å¼•å…¥çš„å˜é‡ä¼šè¢«éšå¼å¯¼å‡ºåˆ°åŽŸè¯ä¸»ä½“之外。比方我们有: .. code-block:: erlang f(X) -> case g(X) of true -> A = h(X); false -> A = k(X) end, ... å˜é‡\ ``A``\ 在其被定义的\ ``case``\ 原è¯ä¹‹åŽä»ç„¶æœ‰æ•ˆã€‚从\ ``if``\ ã€\ ``case``\ 或\ ``receive``\ 原è¯ä¸å¯¼å‡ºå˜é‡æ—¶åº”注æ„一些规则: **在**\ ``if``\ **ã€**\ ``case``\ **或**\ ``receive``\ **原è¯çš„ä¸åŒåˆ†æ”¯ä¸å¼•å…¥çš„å˜é‡é›†åˆå¿…须相åŒï¼Œé™¤éžç¼ºå°‘çš„å˜é‡åœ¨åŽŸè¯å¤–ä¸å†è¢«å¼•ç”¨ã€‚** 例如以下代ç : .. code-block:: erlang f(X) -> case g(X) of true -> A = h(X), B = A + 7; false -> B = 6 end, h(A). 这段代ç 就是éžæ³•çš„ã€‚å› ä¸ºåœ¨å¯¹\ ``true``\ 分支求值时定义了å˜é‡\ ``A``\ å’Œ\ ``B``\ ,而在对\ ``false``\ 分支求值时åªå®šä¹‰äº†\ ``B``\ 。在\ ``case``\ 原è¯ä¹‹åŽï¼Œåˆåœ¨è°ƒç”¨\ ``h(A)``\ ä¸å¼•ç”¨äº†\ ``A``\ ——如果是\ ``fase``\ 分支被求值,则\ ``A``\ 尚未被定义。注æ„如果调用的ä¸æ˜¯\ ``h(A)``\ 而是\ ``h(B)``\ 则这段代ç 就是åˆæ³•çš„ï¼Œå› ä¸º\ ``B``\ 在\ ``case``\ 原è¯çš„两个分支ä¸éƒ½æœ‰å®šä¹‰ã€‚ .. rubric:: 脚注 .. [#] 附录A给出了Erlangçš„å½¢å¼è¯æ³•ã€‚ .. [#] è®¸å¤šäººè®¤ä¸ºç ´å性赋值会导致难以ç†è§£å’Œæ˜“错的ä¸æ¸…晰的程åºã€‚ .. [#] æ ‡è®°\ ``Var``\ |->|\ ``Value``\ 表示å˜é‡\ ``Var``\ 的值为\ ``Value``\ 。 .. [#] å‡è®¾æ‰€æœ‰å‡½æ•°è°ƒç”¨éƒ½ç»“æŸã€‚ .. [#] å³æ˜¯è¯´å‡½æ•°çš„\ **值**\ ä¸Žè°ƒç”¨ä¸Šä¸‹æ–‡æ— å…³ã€‚ .. [#] 有时被称为垃圾箱。 .. [#] 好å§ï¼Œ\ **å‡ ä¹Žæ˜¯**\ ——想想看\ ``factorial(-1)``\ ? .. [#] 如果ä¸çŸ¥é“é€‰å“ªä¸ªï¼Œé€‰æœ€æ¼‚äº®çš„é‚£ä¸ªï¼ .. [*] 译者注:\ ``list/1``\ 在较新版本的Erlangä¸å·²ç»ä¸æŽ¨è使用,应使用\ ``is_list/1``\ 。感谢网å‹\ `å”雀翎 <knuth.fan@qq.com>`_\ 指出。 .. vim:ft=rst ts=4 sw=4 fenc=utf-8 enc=utf-8 et