-

模块与函数

如果一种编程语言只能通过 shell 来运行代码,那么这种语言基本上没什么太大的用处,Erlang 同样可以通过脚本来运行程序。这里有一小段 Erlang 程序。使用合适的文本编辑器将其输入到文件 tut.erl 中。文件名称必须为 tut.erl 不能任意修改,并且需要将其放置于你启动 erl 命令时所在的目录下。如果恰巧你的编辑器有 Erlang 模式的话,那么编辑器会帮助你优雅地组织和格式化你的代码 (参考 Emacs 的 Erlang 模式),不过即使你没有这样的编辑器你也可以很好地管理你自己的代码。Number、ShoeSize 和 Age 都是变量。

创建模块和调用函数:

模块是 erlang 的基本单元。
模块保存在扩展名为 .erl 的文件里。必须先编译才能运行,编译后的模块以 .beam 作为扩展名。
子句没有返回语句,则最后一条表达式的值就是返回值。

  1. -module(geometry). %模块声明,模块名必须与文件名相同。
  2. -export([area/1]). %导出声明,声明可以外部使用的函数
  3. area({rectangle, Width, Height}) -> Width*Height; %子句1
  4. area({square, Side}) -> Side * Side.%子句2

这个函数 area 多个子句,子句之间用;分开。

编译

在控制台中,使用 c(geometry).可以对 geometry.erl 进行编译。
在当前目录生成对应的 geometry.beam 文件。

  1. 17> c("ErlangGame/geometry.erl").
  2. ErlangGame/geometry.erl:1: Warning: Non-UTF-8 character(s) detected, but no encoding declared. Encode the file in UTF-8 or add "%% coding: latin-1" at the beginning of the file. Retrying with latin-1 encoding.
  3. {ok,geometry}

路径

c 的参数,是文件名。带不带扩展名 .erl 都可以。是绝对路径,相对路径,都可以。
例如我的目录是 e:/mywokespace/ErlangGame/geometry.erl

  1. c("e:/mywokespace/ErlangGame/geometry.erl").%使用绝对路径
  2. c("ErlangGame/geometry.erl").%使用相对路径,这个时候我所在的目录是e:/mywokespace/
  3. c(geometry).%使用相对路径、去掉双引号。因为没有.号,可以使用原子。

编译的输出了警告:

ErlangGame/geometry.erl:1: Warning: Non-UTF-8 character(s) detected, but no encoding declared. Encode the file in UTF-8 or add "%% coding: latin-1" at the beginning of the file. Retrying with latin-1 encoding.

这是因为我写了注释,注释是汉字,使用了 UTF-8。去掉的话,就会:
{ok,geometry}
只有这个了。
编译之后,调用模块是不用加这个路径了。

fun:基本抽象单元

定义一个函数

  1. 1> Double = fun(x)->2*x end.
  2. #Fun<erl_eval.6.52032458>
  3. 2> Double(2).
  4. ** exception error: no function clause matching
  5. erl_eval:'-inside-an-interpreted-fun-'(2)

函数定义是成功了,但是怎么调用都报错。
试了好久好久,突然发现x是小写的。在 Erlang 里面,x 就相当于 C++ 的 'x'。是不能做变量的。
变量都是大写开头的。

  1. 3> Three = fun(X)-> 3 * X end.
  2. #Fun<erl_eval.6.52032458>
  3. 4> Three(2).
  4. 6

ok。成功了。

函数可以作为参数

  1. 5> L = [1,2,3,4].
  2. [1,2,3,4]
  3. 6> lists:map(Three, L).
  4. [3,6,9,12]

这里调用了标准库的模块。标准库是已经编译好的,可以直接使用。
直接把函数名传进去就行了。
lists:map 相当于 for 循环


=:=测试是否相等。

  1. 8> lists:filter(fun(X)->(X rem 2)=:=0 end,[1,2,3,4,5,6,7,8]).
  2. [2,4,6,8]

llists:filter 根据条件过滤列表的元素。

函数作为返回值

  1. 9> Fruit = [apple, pear, orange]. %创建一个列表
  2. [apple,pear,orange]
  3. 10> MakeTest = fun(L)->(fun(X)->lists:member(X,L) end) end.%创建一个测试函数。
  4. #Fun<erl_eval.6.52032458>
  5. 11> IsFruit = MakeTest(Fruit).%这里不是函数声明,而是匹配了MakeTest的返回值。
  6. #Fun<erl_eval.6.52032458>
  7. 12> IsFruit(pear).%调用函数
  8. true
  9. 13> lists:filter(IsFruit, [dog, orange, cat, apple, bear]).%过滤
  10. [orange,apple]

MakeTest 内声明了一个函数,因为是最后一个语句,所以被作为返回值。
在模块里面加个函数

  1. -module(test). %模块声明,模块名必须与文件名相同。
  2. -export([area/1,test/0,for/3]). %导出声明,声明可以外部使用的函数
  3. area({rectangle, Width, Height}) -> Width*Height; %子句
  4. area({square, Side}) -> Side * Side.
  5. test() ->
  6. 12 = area({rectangle, 3, 4}),
  7. 144 = area({square, 13}),
  8. tests_worked.