Erlang 和 Elixir的差异
原文: http://elixir-lang.org/crash-course.html
函数调用
Elixir允许你调用函数的时候省略括号, Erlang不行.
| Erlang | Elixir |
|---|---|
some_function(). |
some_function |
sum(A,B) |
sum a,b |
从模块中调用一个函数, 使用不同的语法, 在Erlang, 你可以写:
lists:last([1,2]).
从List模块中调用last函数. 在Elixir中使用.符号代替:符号.
List.last([1,2])
注意. 因为Erlang模块以原子的形式标识, 你可以在Elixir中以如下方式调用Erlang函数.
:lists.sort [1,2,3]
所有Erlang内置函数存在于:erlang模块中.
数据类型
原子
在Erlang中, 原子是以任意小写字母开头的标识符号. 例如ok, tuple, donut. 大写字母开头的任意标识被作为变量名称.
Erlang
im_an_atom.
me_too.
Im_a_var.
X = 10.
Elixir
:im_an_atom
:me_too
im_a_var
x = 10
Module # 原子别名, 扩展为:`Elixir.Module`
还可以创建非小写字母开头的原子, 两种语言的语法差异如下:
Erlang
is_atom(ok). %=> true
is_atom('0_ok'). %=> true
is_atom('Multiple words'). %=> true
is_atom(''). %=> true
Elixir
is_atom :ok #=> true
is_atom :'ok' #=> true
is_atom Ok #=> true
is_atom :"Multiple words" #=> true
is_atom :"" #=> true
元组
元组的语法两种语言相同, 但API有却别.
列表和二进制
Erlang
is_list('Hello'). %=> false
is_list("Hello"). %=> true
is_binary(<<"Hello">>). %=> true
Elixir
is_list 'Hello' #=> true
is_binary "Hello" #=> true
is_binary <<"Hello">> #=> true
<<"Hello">> === "Hello" #=> true
Elixir string 标识一个UTF-8编码的二进制, 同时有一个String模块处理这类书籍.
Elixir假设你的源文件是以UTF-8编码的. Elixir中的string是一个字符列表, 同时有一个:string模块处理这类数据.
Elixir 支持多行字符串(heredocs):
is_binary """
This is a binary
spanning several
lines.
"""
#=> true
关键字列表
包含两个元素的元组列表
Erlang
Proplist = [{another_key, 20}, {key, 10}].
proplists:get_value(another_key, Proplist).
%=> 20
Elixir
kw = [another_key: 20, key: 10]
kw[:another_key]
#=> 20
Map
Erlang
Map = #{key => 0}. % 创建Map
Updated = Map#{key := 1}. % 更新Map中的值
#{key := Value} = Updated. % 匹配
Value =:= 1.
%=> true
Elixir
map = %{:key => 0} # 创建Map
map = %{map | :key => 1} # 更新Map中的值
%{:key => value} = map # 匹配
value === 1
#=> true
注意:
1.key: 和 0之间一定要有一个空格, 如下:
iex(2)> map = %{key:0}
**(SyntaxError) iex:2: keyword argument must be followed by space after: key:
iex(2)> map = %{key: 0}
%{key: 0}
2.所有的key必须是原子类型才能这么用.
正则表达式
Elixir支持正则表达式的字面语法. 这样的语法允许正则表达式在编译时被编译而不是运行时进行编译, 并且不要求转义特殊的正则表达式符号:
Erlang
{ ok, Pattern } = re:compile("abc\\s").
re:run("abc ", Pattern).
%=> { match, ["abc "] }
Elixir:
Regex.run ~r/abc\s/, "abc "
#=> ["abc "]
正则表达式还能用在heredocs当中, 提供了一个定义多行正则表达式的便捷的方法:
Regex.regex? ~r"""
This is a regex
spanning several
lines.
"""
模块
每个erlang模块保存在其自己的文件中, 并且有如下结构:
-module(hello_module).
-export([some_fun/0, some_fun/1]).
% A "Hello world" function
some_fun() ->
io:format('~s~n', ['Hello world!']).
% This one works only with lists
some_fun(List) when is_list(List) ->
io:format('~s~n', List).
% Non-exported functions are private
priv() ->
secret_info.
这里我们创建一个名为hello_module的模块. 其中我们定义了三个函数, 前两个用于其他模块调用, 并通过export指令导出. 它包含一个要导出的函数列表, 其中没个函数的书写格式为<function name>/<arity>. arity标书参数的个数.
上面的Elixir等效代码为:
defmodule HelloModule do
# A "Hello world" function
def some_fun do
IO.puts "Hello world!"
end
# This one works only with lists
def some_fun(list) when is_list(list) do
IO.inspect list
end
# A private function
defp priv do
:secret_info
end
end
在Elixir中, 还可以在一个文件中定义多个模块, 以及嵌套模块.
defmodule HelloModule do
defmodule Utils do
def util do
IO.puts "Utilize"
end
defp priv do
:cant_touch_this
end
end
def dummy do
:ok
end
end
defmodule ByeModule do
end
HelloModule.dummy
#=> :ok
HelloModule.Utils.util
#=> "Utilize"
HelloModule.Utils.priv
#=> ** (UndefinedFunctionError) undefined function: HelloModule.Utils.priv/0
函数语法
Erlang 图书的这章提供了模式匹配和函数语法的详细描述. 这里我简单的覆盖一些要点并提供Erlang和Elixir的代码示例:
模式匹配
Erlang
loop_through([H|T]) ->
io:format('~p~n', [H]),
loop_through(T);
loop_through([]) ->
ok.
Elixir
def loop_through([h|t]) do
IO.inspect h
loop_through t
end
def loop_through([]) do
:ok
end
当定义一个同名函数多次的时候, 没个这样的定义称为分句. 在Erlang中, 分句总是紧挨着的, 并且由分号;分割. 最后一个分句通过点.终止.
Elixir并不要求使用标点符号来分割分句, 但是他们必须分组在一起(同名函数必须上下紧接着)
标识函数
在Erlang和Elixir中, 函数不仅仅由名字来标识, 而是由名字和参数的个数共同来标识一个函数. 在下面两个例子中, 我们定义了四个不同的函数(全部名为sum, 不同的参数个数)
Erlang
sum() -> 0.
sum(A) -> A.
sum(A, B) -> A + B.
sum(A, B, C) -> A + B + C.
Elixir
def sum, do: 0
def sum(a), do: a
def sum(a, b), do: a + b
def sum(a, b, c), do: a + b + c
基于某些条件, Guard表达式(Guard expressions), 提供了一个精确的方式定义接受特定取值的函数
Erlang
sum(A, B) when is_integer(A), is_integer(B) ->
A + B;
sum(A, B) when is_list(A), is_list(B) ->
A ++ B;
sum(A, B) when is_binary(A), is_binary(B) ->
<<A/binary, B/binary>>.
sum(1, 2).
%=> 3
sum([1], [2]).
%=> [1,2]
sum("a", "b").
%=> "ab"
Elixir
def sum(a, b) when is_integer(a) and is_integer(b) do
a + b
end
def sum(a, b) when is_list(a) and is_list(b) do
a ++ b
end
def sum(a, b) when is_binary(a) and is_binary(b) do
a <> b
end
sum 1, 2
#=> 3
sum [1], [2]
#=> [1,2]
sum "a", "b"
#=> "ab"
默认值
Erlang不支持默认值
Elixir 允许参数有默认值
def mul_by(x, n \\ 2) do
x * n
end
mul_by 4, 3 #=> 12
mul_by 4 #=> 8
匿名函数
匿名函数以如下方式定义:
Erlang
Sum = fun(A, B) -> A + B end.
Sum(4, 3).
%=> 7
Square = fun(X) -> X * X end.
lists:map(Square, [1, 2, 3, 4]).
%=> [1, 4, 9, 16]
当定义匿名函数的时候也可以使用模式匹配.
Erlang
F = fun(Tuple = {a, b}) ->
io:format("All your ~p are belong to us~n", [Tuple]);
([]) ->
"Empty"
end.
F([]).
%=> "Empty"
F({a, b}).
%=> "All your {a,b} are belong to us"
Elixir
f = fn
{:a, :b} = tuple ->
IO.puts "All your #{inspect tuple} are belong to us"
[] ->
"Empty"
end
f.([])
#=> "Empty"
f.({:a, :b})
#=> "All your {:a, :b} are belong to us"
一类函数
匿名函数是第一类值, 他们可以作为参数传递给其他函数, 也可以作为返回值. 这里有一个特殊的语法允许命名函数以相同的方式对待:
Erlang
-module(math).
-export([square/1]).
square(X) -> X * X.
lists:map(fun math:square/1, [1, 2, 3]).
%=> [1, 4, 9]
Elixir
defmodule Math do
def square(x) do
x * x
end
end
Enum.map [1, 2, 3], &Math.square/1
#=> [1, 4, 9]
Partials in Elixir
Elixir supports partial application of functions which can be used to define anonymous functions in a concise way:
Enum.map [1, 2, 3, 4], &(&1 * 2)
#=> [2, 4, 6, 8]
List.foldl [1, 2, 3, 4], 0, &(&1 + &2)
#=> 10
Partials also allow us to pass named functions as arguments.
defmodule Math do
def square(x) do
x * x
end
end
Enum.map [1, 2, 3], &Math.square/1
#=> [1, 4, 9]
控制流
The constructs if and case are actually expressions in both Erlang and Elixir, but may be used for control flow as in imperative languages.
Case
The case construct provides control flow based purely on pattern matching.
Erlang
case {X, Y} of
{a, b} -> ok;
{b, c} -> good;
Else -> Else
end
Elixir
case {x, y} do
{:a, :b} -> :ok
{:b, :c} -> :good
other -> other
end
If
Erlang
Test_fun = fun (X) ->
if X > 10 ->
greater_than_ten;
X < 10, X > 0 ->
less_than_ten_positive;
X < 0; X =:= 0 ->
zero_or_negative;
true ->
exactly_ten
end
end.
Test_fun(11).
%=> greater_than_ten
Test_fun(-2).
%=> zero_or_negative
Test_fun(10).
%=> exactly_ten
Elixir
test_fun = fn(x) ->
cond do
x > 10 ->
:greater_than_ten
x < 10 and x > 0 ->
:less_than_ten_positive
x < 0 or x === 0 ->
:zero_or_negative
true ->
:exactly_ten
end
end
test_fun.(44)
#=> :greater_than_ten
test_fun.(0)
#=> :zero_or_negative
test_fun.(10)
#=> :exactly_ten
区别:
cond允许左侧为任意表达式, erlang只允许guard子句.cond中的条件只有在表达式为nil和false的时候为false, 其他情况一律为true, Erlang为一个严格的布尔值
Elixr还提供了一个简单的if结构
if x > 10 do
:greater_than_ten
else
:not_greater_than_ten
end
发送和接受消息
Erlang
Pid = self().
Pid ! {hello}.
receive
{hello} -> ok;
Other -> Other
after
10 -> timeout
end.
Elixir
pid = Kernel.self
send pid, {:hello}
receive do
{:hello} -> :ok
other -> other
after
10 -> :timeout
end
添加Elixir到现有的Erlang程序
Rebar集成
如果使用Rebar,可以把Elixir仓库作为依赖.
https://github.com/elixir-lang/elixir.git
Elixir实际上是一个Erlang的app. 它被放在lib目录中, rebar不知道这样的目录结构. 因此需要制定Elixir的库目录.
{lib_dirs, [
"deps/elixir/lib"
]}.
转自:https://segmentfault.com/a/1190000004882064
Erlang 和 Elixir的差异的更多相关文章
- [Erlang 0108] Elixir 入门
Erlang Resources里面关于Elixir的资料越来越多,加上Joe Armstrong的这篇文章,对Elixir的兴趣也越来越浓厚,投入零散时间学习了一下.零零散散,测试代码写了一些,Ev ...
- Erlang 和 Elixir 互相调用 (转)
lixr设计目标之一就是要确保兼容性,可以兼容Erlang和其生态系统.Elixir和Erlang 都是运行同样的虚拟机平台(Erlang Virtual Machine).不管是在Erlang使用E ...
- Install Erlang and Elixir in CentOS 7
In this tutorial, we will be discussing about how to install Erlang and Elixir in CentOS 7 minimal s ...
- CentOS 7.7安装Erlang和Elixir
安装之前,先看一下它们的简要说明 Erlang Erlang是一种开源编程语言,用于构建对高可用性有要求的大规模可扩展的软实时系统.它通常用于电信,银行,电子商务,计算机电话和即时消息中.Erlang ...
- [Erlang 0113] Elixir 编译流程梳理
注意:目前Elixir版本还不稳定,代码调整较大,本文随时失效 之前简单演示过如何从elixir ex代码生成并运行Erlang代码,下面仔细梳理一遍elixir文件的编译过程,书接上文,从 ...
- [Erlang 0112] Elixir Protocols
Why Elixir 为什么要学习Elixir?答案很简单,为了更好的学习Erlang.这么无厘头的理由? Erlang语法设计几乎没有考虑过取悦开发者,所以学习之初的门槛略高.对于已经克服了最初 ...
- [Erlang 0114] Erlang Resources 小站 2013年7月~12月资讯合集
Erlang Resources 小站 2013年7月~12月资讯合集,方便检索. 附 2013上半年盘点: Erlang Resources 小站 2013年1月~6月资讯合集 小站地 ...
- Erlang 参考资料
Erlang 官方文档 Distributed Erlang Erlang 教程中文版 %设定模块名 -module(tut17). %导出相关函数 -export([start_ping/1, st ...
- 简单Elixir游戏服务器-安装Elixir
用WebInstaller 安装半天也没下载成功文件. 改成直接下载erlang 和 elixir 预编译包了. 安装很简单,最后设置好环境变量. cmd 执行 elixir -v 最后顺便下载了个g ...
随机推荐
- Memcached网络模型
之前用libevent开发了一个流媒体服务器.用线程池实现的.之后又看了memcached的网络相关实现,今天来整理一下memcached的实现流程. memcached不同于Redis的单进程单线程 ...
- 安装完office2016 64位后,在安装visio时,报错,无法安装,
安装环境要求: 系统要求:win8,win10等: office要求:sw(批量版)不能和cn(零售版).365版混装.-------重点注意事项 一定要注意批量版和零售版的区别,各版本之间绝对不允许 ...
- Myeclipse中文件已经上传到server文件夹下,文件也没有被占用,可是页面中无法读取和使用问题的解决方法
这个问题是因为Myeclipse中文件不同步引起的.在Myeclipse中,project文件是由Myeclipse自己主动扫描加入的,假设在外部改动了project文件夹中的文件但又关闭了自己主动刷 ...
- kubelet分析
kubelet是k8s中节点上运行的管理工具,它负责接受api-server发送的调度请求,在Node上创建管理pod,并且向api-server同步节点的状态.这篇文章主要讲讲kubelet组件如何 ...
- SSH 错误解决案例1:Read from socket failed: Connection reset by peer
今天早上天天连接的开发机突然报出连接错误. 这个错误是SSH最常见错误,造成的原因也是千奇百怪(具体可goole),下面描述我的server的问题: 客户端报错 [root@server]# ssh ...
- HDU 4008 Parent and son LCA+树形dp
题意: 给定case数 给定n个点的树,m个询问 以下n-1行给出树边 m个询问 x y 问:以x为根.y子树下 y的最小点标的儿子节点 和子孙节点 思路: 用son[u][0] 表示u的最小儿子 s ...
- Java代码格式
东汉大臣陈蕃有一则这种故事,"一屋不扫何以扫天下",寓意来表明一个大丈夫,假设连自己的居室都不能打扫干净,怎么胸怀天下.<代码整洁之道>就是来劝诫我们程序猿写出更优秀的 ...
- Linux启动U盘制作
Linux目前最好的u盘启动工具之一,下面介绍它的用法,首先下载Linux live OK了,一步一步跟我步骤走! 启动时,选择需要用的U盘 步骤二,就选择安装源即可(一般为ISO文件) 最后进行步骤 ...
- hibernate.cfg.xml文件连接mySql、Oracle、SqlServer配置
1.连接mySql,文件配置如下: <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibe ...
- Odoo8中“更多”下拉菜单选项指定后台执行代码
在Odoo8中的仓库模块,根据每日最小安全库存数量,系统会自动生成一些补货单,而且是一个产品会生成一笔,如果产品比较多,这里生成的补货单也会很多. 如果这里的补货单没有即时处理,那相同产品后续不会再生 ...