Elixir初体验

在京东上搜Elixir,会发现Elixir是一种琴弦的品牌,然而我今天想讲的Elixir是一种编程语言。它的Logo如下

Elixir

早就有学习这门语言的打算,只是事情太多,忙着忙着就忘了。公司最近的技术分享中,明哥分享了一个关于Phoenix(基于Elixir的Web开发框架)跟Rails的比较的话题,重新燃起了我对这门语言的好奇心。接下来让我们一起简单的来看看Elixir这门语言。

1. Elixir是什么

我们先来看看官方的解释

Elixir is a dynamic, functional language designed for building scalable and maintainable applications.

Elixir 是一门动态的函数式编程语言,主要是用来构建可扩展,可维护的应用程序。好吧,把函数式去掉的话Ruby也可以做到。Ruby是一门动态的命令式编程语言,可以用来构建可扩展及可维护的应用程序。不过Ruby设计的初衷并不是为了解决什么问题,它的初衷是Happy Coding!

Elixir leverages the Erlang VM, known for running low-latency, distributed and fault-tolerant systems, while also being successfully used in web development and the embedded software domain.

Elixir运行在Erlang虚拟机上,以低负载,分布式和容错系统而闻名。已经成功应用在Web开发领域,以及嵌入式软件领域。这也算是编程语言的另一个发展方向吧,除了直接用系统级编程语言(如C,C++,Go)来开发编程语言,我们还可以在比较成熟的虚拟系统上构造我们想要的编程语言。比如JavaVM之上有人发明了Clojure,Scale这些函数式编程语言(身边的人好像比较喜欢Clojure),而有位Ruby英雄在ErlangVM上实现了Elixir。

2. 安装Elixir

安装教程没有能比官方文档更加详细的了,我这里就不重复说了,我就说说我在Mac上安装的时候遇到的比较尴尬的问题吧。

Elixir是运行在Erlang环境下的编程语言,当我们用HomeBrew安装Elixir的时候,它也会顺势帮你安装Erlang。

想想很久之前我们用HomeBrew安装了Elixir,以及配套的Erlang环境。然后我们卸载了Elixir,却留下了Erlang。几个月后我们重新安装Elixir这个时候,也配套安装了最新版本的Erlang,于是事故发生了。

两个不同版本的Erlang
> erl
Erlang/OTP 19 [erts-8.3] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]

Eshell V8.3  (abort with ^G)
1>

我们的系统同时保留着两个版本的Erlang,以及新版本的Elixir。而系统还默认引用这旧版本的Erlang,这表明了我们会把新版本的Elixir运行在旧版本的Erlang上面,你可能就会得到如下错误。

> iex
2017-11-02 21:54:29 Loading of ~ts failed: ~p

    "/usr/local/Cellar/elixir/1.5.2/bin/../lib/iex/ebin/Elixir.IEx.CLI.beam"
    badfile
2017-11-02 21:54:29 ~s~n
    "beam/beam_load.c(1287): Error loading module 'Elixir.IEx.CLI':\n  mandatory chunk of type 'Atom' not found\n\n"
2017-11-02 21:54:29 crash_report
    initial_call: {supervisor_bridge,user_sup,['Argument__1']}
    pid: <0.47.0>
    registered_name: []
    error_info: {exit,{undef,[{'Elixir.IEx.CLI',start,[],[]},{user_sup,start_user,3,[{file,"user_sup.erl"},{line,100}]},{user_sup,init,1,[{file,"user_sup.erl"},{line,49}]},{supervisor_bridge,init,1,[{file,"supervisor_bridge.erl"},{line,80}]},{gen_server,init_it,6,[{file,"gen_server.erl"},{line,328}]},{proc_lib,init_p_do_apply,3,[{file,"proc_lib.erl"},{line,247}]}]},[{gen_server,init_it,6,[{file,"gen_server.erl"},{line,352}]},{proc_lib,init_p_do_apply,3,[{file,"proc_lib.erl"},{line,247}]}]}
    ancestors: [kernel_sup,<0.34.0>]
    messages: []
    links: [<0.35.0>]
    dictionary: []
    trap_exit: true
    status: running
    heap_size: 610
    stack_size: 27
    reductions: 145
2017-11-02 21:54:29 supervisor_report
    supervisor: {local,kernel_sup}
    errorContext: start_error
    reason: {undef,[{'Elixir.IEx.CLI',start,[],[]},{user_sup,start_user,3,[{file,"user_sup.erl"},{line,100}]},{user_sup,init,1,[{file,"user_sup.erl"},{line,49}]},{supervisor_bridge,init,1,[{file,"supervisor_bridge.erl"},{line,80}]},{gen_server,init_it,6,[{file,"gen_server.erl"},{line,328}]},{proc_lib,init_p_do_apply,3,[{file,"proc_lib.erl"},{line,247}]}]}
    offender: [{pid,undefined},{id,user},{mfargs,{user_sup,start,[]}},{restart_type,temporary},{shutdown,2000},{child_type,supervisor}]
2017-11-02 21:54:29 crash_report
    initial_call: {application_master,init,['Argument__1','Argument__2','Argument__3','Argument__4']}
    pid: <0.33.0>
    registered_name: []

这是个错误示范,可能你也会遇到类似的问题,报错信息不会完全一样,不过应该也差不多。究其原因就如上面所说Eixir版本跟Erlang版本不兼容,当我们想在老版本的Erlang上跑新版本的Elixir就出问题了。

解决方法有两个

1) 切换Erlang的默认版本,换成我们期待的最新版本的Erlang

我们通过HomeBrew的命令

brew switch erlang 20.1.3

只需要简单地把默认Erlang运行环境指定到我们需要的最新版本的,然后重新运行Elixir就能够进入我们期待的REPL环境了。

> iex
Erlang/OTP 20 [erts-9.1.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]

Interactive Elixir (1.5.2) - press Ctrl+C to exit (type h() ENTER for help)

2) 卸载Elixir,以及所有版本的Erlang,重新安装

这种方法简单粗暴,如果我们不需要多版本的Erlang的话我建议可以把他们都移除掉,毕竟一个Erlang包会占用掉系统200多MB的磁盘空间。

通过brew命令的uninstall指令,加上--force标识就能够移除所有版本的Erlang

brew uninstall --force erlang

如果单独移除Erlang而不移除Elixir的话就会有以下的异常信息

Error: Refusing to uninstall /usr/local/Cellar/erlang/20.1.3
because it is required by elixir 1.5.2, which is currently installed.
You can override this and force removal with:
  brew uninstall --ignore-dependencies erlang

前面也说了Elixir依赖于Erlang,当我们只想单独卸载被依赖的Erlang的时候就会有这个警告,我不建议用它的命令保留Elixir而单独移除Erlang,毕竟该清理的还是要清理干净,重新安装也耗费不了多少时间。我们只需要依次运行以下命令

brew uninstall elixir
brew uninstall --force erlang
brew install elixir

把Elixir以及所有版本的Erlang删除之后,再重新安装Elixir,我们就可以体验最新版本的Elixir,并开始美妙的Elixir之旅。

> iex
Erlang/OTP 20 [erts-9.1.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]

Interactive Elixir (1.5.2) - press Ctrl+C to exit (type h() ENTER for help)

3. 第一条Elixir程序

又到了大家喜闻乐见的活动了,第一条程序总是会让人热血沸腾。不过咱门今天就别上HelloWorld了吧,来简单写一个脚本。

First

(1) 编译模式

写习惯了解释性语言,已经很久没试过编译代码了。想想以前写C的时候运行之前都是需要先编译,然后执行生成的二进制文件。现在我们来看看Elixir是如何操作的。

Elixir有个约定,需要编译的文件以.ex后缀名结尾,而直接运行的脚本则.exs后缀名结尾,我们也依照这个约定吧(即便我们都知道在Unix操作系统里面后缀名是什么根本就无所谓)。这里我们创建一个文件math.ex

# math.ex

defmodule Math do
  def sum(a, b) do
    a + b
  end
end

这种编码风格跟Ruby很像,实际上我们定义了一个包含sum方法的模块Math,然后运行编译命令

> elixirc math.ex

编译成功后会生成名为Elixir.Math.beam的文件

> ls
Elixir.Math.beam math.ex

这个就是编译后的字节码文件,熟悉Java的人应该知道Java里面也有类似的存在。然后我们在当前目录下面运行iex进行REPL环境,就能直接使用这个Math模块了

> iex
Erlang/OTP 20 [erts-9.1.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]

Interactive Elixir (1.5.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> Math.sum(1,2)
3

接下来再简单看看脚本模式。

(2) 脚本模式

每次都要编译那多麻烦啊,很好,这也是我不喜欢部分编译型语言的原因之一(只是部分)---它们甚至连REPL环境都没有。Elixir考虑到了这一点,按照习俗我们在新目录下创建一个math.exs的脚本文件

# math.exs

defmodule Math do
  def sum(a, b) do
    a + b
  end
end

PS: 内容跟编译模式中的文件一样,只是后缀名不同。

> ls
math.exs

然后我们可以直接用相关的命令运行对应脚本

> elixir math.exs

由于我们math.exs里面只是定义了一个简单的模块和方法,并没有更多的逻辑,所以这次执行也看不出什么效果。不过在Elixir机制中我们可以像下面这样操作,直接地把目标文件加载到REPL环境中

> iex math.exs
Erlang/OTP 20 [erts-9.1.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]

Interactive Elixir (1.5.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> Math.sum(1,2)
3

可以看到运行结果跟之前编译模式一样的只是少了手动编译那一步,这有利于我们对源码文件进行简单地测试,而不需要每次测试的时候都手动编译一次。

官网的建议是平时开发业务逻辑代码都以.ex后缀名结尾,最后需要被编译成字节码(这可能是性能方面考虑吧)。而编写日常单元测试或者配置信息则以.exs后缀名来结尾。

4. 总结

对这门语言的学习,大概只是看了4-5天的入门指南。它是否真如文档所说能够用来构建可扩展性高的系统,以及它是否真的有传闻说的那样地高性能呢?这一点还有待考证。

剁手

不过经过这两天的学习,我觉得这是一门挺值得入手的语言,特别是对于Ruby系的朋友来说。如果说Haskell是有Python风格的纯函数式编程语言(他们大写的None让我印象深刻),那我觉得Elixir就是有Ruby风格的函数式编程语言了。不过即便它语法风格设计方面跟Ruby很像,但Elixir就是Elixir,相信你会从中感受到与Ruby不一样的编程体验。

Happy Coding and Writing!!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容