Skip to content

Instantly share code, notes, and snippets.

@loggerhead
Last active June 22, 2018 12:48
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save loggerhead/48facfaab6db640c2b3f to your computer and use it in GitHub Desktop.
Save loggerhead/48facfaab6db640c2b3f to your computer and use it in GitHub Desktop.
Erlang快速入门
% bar.erl
-module(bar).
-include("bar.hrl").
-compile(export_all).
distance(P) when is_number(P#point.x), is_number(P#point.y) ->
math:sqrt(P#point.x*P#point.x + P#point.y*P#point.y).
% record 在 function clause 中的匹配很违背直觉
% 仅匹配 `#point.y == 1`,而不管 `#point.x` 是不是 `0`
test(#point{y = 1}) -> io:fwrite("x=? y=1~n");
% 仅匹配 `#point.x == 1`,而不管 `#point.y` 是什么值
test(#point{x = 1}) -> io:fwrite("x=1 y=?~n").
test() ->
P1 = #point{x = 1, y = 0},
P2 = {point, 1, 0},
case distance(P1) =:= distance(P2) of
true -> ok;
false -> error("Oh My God! This is impossible!")
end,
test(#point{x = whatever, y = 1}), % x=? y=1
test(#point{x = 1, y = 1}), % x=? y=1
test(#point{x = 1, y = whatever}). % x=1 y=?
% bar.hrl
% record 将元组中的元素绑定到特定的名称
-record(point, {x = 0, y}).
% 等价于 {point, X = 0, Y = undefined}
% catcher.erl
-module(catcher).
-compile(export_all).
% `throw`, `exit`, `error` 三者都能产生异常
do_something(throw) -> throw(lol); % ** exception throw: lol
do_something(exit) -> exit(lol); % ** exception exit: lol
do_something(error) -> error(lol); % ** exception error: lol
do_something(X) -> X.
normal_catcher(X) ->
try do_something(X) of
Result -> io:format("do_something(~p) => ~p~n", [X, Result])
catch
throw:E -> io:format("catch throw: ~p~n", [E]);
exit:E -> io:format("catch exit: ~p~n", [E]);
error:E -> io:format("catch error: ~p~n", [E])
end.
all_catcher(X) ->
try do_something(X) of
Result -> io:format("do_something(~p) => ~p~n", [X, Result])
catch
% 省略错误类型
% 默认为 throw 类型
E -> io:format("catch you: ~p~n", [E])
after
io:format("after `try...catch`~n")
end.
simple_catcher(X) ->
% 将异常转换为一个描述异常的元组
% 如果没有异常,则返回表达式的值
catch do_something(X).
-module(if_case).
-compile(export_all).
% `if` 类似于 guard,并且语法和 guard 一致
hi_if(X) ->
% `if` 也有返回值
Result = if
% 必须匹配所有的逻辑,否则会 crash
X > 0 -> positive;
X == 0 -> zero;
% 匹配剩下的所有可能
true -> negative
end,
io:format("if expression result is '~p'~n", [Result]).
% `case` 类似于函数头部,其余部分和 `if` 几乎一样
hi_case(X) ->
Result = case X of
X when X > 0 -> positive;
X when X == 0 -> zero;
% 匹配剩下的所有可能
_ -> negative
end,
io:format("case expression result is '~p'~n", [Result]).
% m.erl
-module(m).
-export([start_echo/0, start_hurry/0]).
echo() ->
receive
{From, Msg} ->
io:format("~p => ~p: ~p~n", [From, self(), Msg]),
From ! Msg,
% 循环接收消息
echo()
% 如果10秒内没收到消息,就执行 after 语句
after 10000 ->
io:format("quit echo process~n")
end.
% `after 0` 的逻辑类似于:
% if is_not_empty(message_queue)
% receive()
% else
% after()
do_hurry() ->
receive
Msg ->
io:format("message: '~p'~n", [Msg]),
do_hurry()
after 0 ->
io:format("no more message, quit~n")
end.
% 等待10秒后从消息队列中取出所有消息
hurry(Wait) ->
timer:sleep(Wait),
do_hurry().
start_echo() ->
% 调用 `spawn` 启动新进程,并返回一个pid(进程标识符)
% 在 `erl` 中调用为 `spawn(Function)`,在模块中为 `spawn(fun Function/0)`
spawn(fun echo/0).
start_hurry() ->
spawn(fun() -> hurry(10000) end).
% mymath.erl
-module(mymath).
-compile(export_all).
% 自定义的宏
-define(ONE, 1).
-define(ADD(X, Y), X+Y).
test() ->
io:format("predefined macros: ~n"),
% 预定义的宏
io:format("~p ~p ~p ~p ~p~n", [?MODULE, ?MODULE_STRING, ?FILE, ?LINE, ?MACHINE]),
% `?MACRO` 调用宏
io:format("one=~p add(1,2)=~p~n", [?ONE, ?ADD(1, 2)]).
% mymethod.erl
-module(mymethod).
% 要想在外部调用模块中的函数,首先得将函数导出
% -export([Function1/Arity, ..., FunctionN/Arity]).
-export([hi/0, all_the_same/3, is_adult/1, is_triangle/3, is_num/1, bro/1, bro/0, yo/1, sum/1]).
% 调试的时候可以使用下面的语句导出所有函数
% -compile(export_all).
% 不需要 `end`
hi() ->
"hello, world".
% 按函数分句的先后顺序进行模式匹配
% 找到第一个参数匹配的分句时,执行该分句下的表达式
% 分号表分句的结束,句号表整个函数的结束
all_the_same(X, X, X) -> true;
% `_` 是匿名变量
all_the_same(_, _, _) -> false.
is_adult(Age) when Age < 18 -> false;
is_adult(_) -> true.
% 逗号在 guard 中的作用类似于 `and`
is_triangle(A, B, C) when A+B > C, B+C > A, A+C > B -> true;
is_triangle(_, _, _) -> false.
% 分号在 guard 中的作用类似于 `or`
is_num(X) when is_integer(X); is_float(X) -> true;
is_num(_) -> false.
bro(Girlfriend) when Girlfriend == girl ->
io:format("fall in love with ~p~n", [Girlfriend]);
% 若参数未被使用,编译时会发出警告:`Warning: variable 'Girl' is unused`
% 如果参数名以下划线开头,则不会警告
bro(_Girl) ->
io:format("cheat!~n").
% 参数数目不同但同名的函数没有任何关系
bro() ->
io:format("I'm a single dog~n").
% 根据参数的模式匹配执行不同的分句
yo(brother) ->
io:format("Hi, man!~n");
yo(friend) ->
io:format("How are you?~n");
yo(People) ->
io:format("Are you \"~p\"?~n", [People]).
% 计算列表的和
sum(L) -> sum(L, 0). % 句号
sum([], Result) -> Result; % 分号
sum([H|T], Result) -> sum(T, H+Result). % 又是句号,为什么?
% 模块属性以 `-` 开头
% module 属性是必须的,且参数必须与除去后缀的文件名一致
-module(test).
% import 属性用来导入其他模块的函数,然后才能在模块中使用
% -import(Module, [Function1/Arity, ..., FunctionN/Arity]).
% 其中 Arity 是函数的参数数目
@loggerhead
Copy link
Author

编译

erlc *.erl

运行

直接在 erl 中使用,不需要再用 c 进行编译了。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment