在IT世界里,没有银弹,但却有神奇的仙丹(Elixir)。我不知道是什么灵感刺激这门语言的创造者José Valim想到了这么酷的命名,但这枚仙丹确实经由多种神奇的灵药炼制而成,这些灵药包括Erlang、Ruby、Clojure、Haskell。

品尝这枚仙丹确实令人飘飘欲仙,至少,我在浅尝Elixir时,这种奇妙的感觉一直萦绕在我心间,怦然心动因而不舍离去。或许如Erlang之父Joe Armstrong所说,是“一种先行于逻辑的内心感性的感觉”;又或者如Dave Thomas形容的,那是让人“坠入爱河”的感觉。

大爱Elixir。

我之所以爱上Elixir,大约还是因为Ruby的缘故。我并非Ruby的狂热追随者,甚至没有从事太多Ruby相关的项目,但我至今在编写脚本时,Ruby依旧是我的首选。在动态语言中,我甚喜爱Ruby相对简洁的语法。当我看到Elixir时,那种似曾相识的感觉让我心动。

虽然说Elixir的炼制来自各位前辈留下的丹方灵药,然而从成丹之日起,Elixir就是Elixir,她已经具有了完整的语言性格。就我看来,Elixir真正称得上是“性感”。当然,这一大半要归功于Erlang美丽的英伦风情(Erlang之父Joe Armstrong是英国人),就Erlang的高颜值打底,只需再加上几点妩媚,几分妖娆,风采就变得性感撩人了。

并发与分布式

Elixir对并发与分布式的支持,就是正宗的英伦风情,这是从Erlang延续下来的最强悍基因。Elixir建立在Erlang虚拟机(BEAM)之上,使用Erlang的进程,如原生进程那样在所有的处理器中运行,然而开销却非常小。与Erlang一样,Elixir可以通过spawn轻松地创建进程:

spawn fn -> 1 + 2 end

Elixir或者说Erlang的进程依靠消息传递完成通信。进程接收到的消息实际上是获取的一份消息副本,这就使得接收方能够与发送方解耦,接收方对消息的任何操作不会影响接收方。

send self, {:hello, "world"}receive do{:hello, msg} -> msg{:world, msg} -> "won't match"
end

Elixir的核心继承自Erlang,自然就继承了对OTP(Open Telecom Platform)的支持。OTP是一个很大的课题,包括进程链接、监控以及分布式支持(我正在学习《Erlang/OTP并发编程实战》,希望从Erlang根源上理解OTP)。Elixir对OTP的支持包括Agent、Task、GenServer以及Supervisor与Application。其中,Agent与Task是Elixir对OTP特性的抽象,而GenServer则更加通用。

在Elixir创建OTP服务器非常简单,只需要use GenServer即可。它主要的方法为handle_call(request, from, state)与handle_cast(request, state)。如果客户端发送的请求需要响应时,则消息形式为call,如果为单向调用,则形式为cast。

考虑进程的健壮性问题,在编写OTP应用时,可能还需要对进程进行监督。基于Actor模型,父进程将负责监督由其创建的所有子进程,下面的代码是Elixir官方提供的Supervisor代码:

defmodule KV.Supervisor douse Supervisordef start_link doSupervisor.start_link(__MODULE__, :ok)enddef init(:ok) dochildren = [worker(KV.Registry, [KV.Registry]),supervisor(KV.Bucket.Supervisor, [])]supervise(children, strategy: :rest_for_one)end
end

KV.Supervisor为监督进程,其子进程分别为KV.Registry与KV.Bucket.Supervisor,监督策略为rest_for_one。

至于分布式支持,在Elixir其实是水到渠成的事情,因为它的核心是进程间通信,而进程所在的节点位置,对于用户而言是透明的。

模式匹配

模式匹配是Elixir最妖娆的部分,虽然很多函数式语言都有模式匹配,但Elixir却把模式匹配融入到其血肉之中(其实是延续了Erlang的模式匹配特色)。即使是一个赋值语句,也是模式匹配的一部分。在Elixir中,=符号其实被称之为匹配运算符(match operator)。所以你可以写出违反程序员常规的1 = x:

iex> 1 = x
1
iex> 2 = x
** (MatchError) no match of right hand side value: 1

模式匹配在Elixir中被广泛地运用到解构(destructuring )复杂的数据结构,例如Tuple、List等。当然case进行的模式匹配更是它最常见的使用场景。

函数与模式匹配的结合才是体现妖娆性的关键点,如果再结合guard clause,那就真正让人销魂了。

大多数语言的函数定义是支持函数重载的,这取决于参数的类型、个数与顺序。在动态语言中没有类型,则与个数与顺序相关。这些参数在定义时皆为形参(部分语言支持默认参数值,Elixir也支持,甚至可以将表达式作为默认参数),在调用时才传入实参。

但是,Elixir则不然,因为Elixir没有赋值的概念,因此在传递参数时,并非赋值的语义,而是匹配的语义。因而出现如下的函数定义,你不要感到诧异哦:

defmodule Factorial dodef of(0), do: 1def of(n), do: n * of(n-1)
end

在Elixir语义中,这两个定义实则是同一个函数,当调用of函数时,传入的参数会与第一个定义进行匹配,如果匹配不成功,则匹配第二个定义。利用这种模式匹配,既可以规避实现上的if分支,又可以更好地体现递归的语义。

Meyer非常强调软件开发中对“契约”的遵循,在他设计的语言Eiffel中,前置条件与后置条件作为了语法糖中的一等公民被支持。Erlang的guard Cluase与Eiffel的前置条件非常相似,Elixir也保留了这一语法特性。例如在前面的阶乘算法中,我们可以通过guard clause避免传入错误的负数:

defmodule Factorial dodef of(0), do: 1def of(n) when n > 0, do: n * of(n-1)
end

管道运算符

让Elixir展现其妩媚一面的,是超级性感的管道运算符。她让整段代码瞬间变得可爱起来。有了她,我们就不用再陷入可怕的函数嵌套地狱中了。Dave Long在博文Playing with Elixir Pipes中给出了一个颇有对照意义的例子。代码功能是从conn取得Request的header,并判断它是否有效。如果有效就返回conn,否则终止,并返回Not Authorized。

如果没有管道运算符,就得承受嵌套函数调用的惊悚感:

signature = List.first(get_req_header(conn, "x-twilio-signature"))
is_valid = Validator.validate(url_from_conn(conn), conn.params, signature)
if is_valid do  conn
else  halt(send_resp(conn, 401, "Not authorized"))
end

这样的代码完全违反人类直觉,因为你得从函数最里边阅读,然后再层层往外逃逸。是否有一种被紧紧捆绑了的感觉呢?当然,在很多语言中我们都无奈地接受了这一点,已经被虐得习以为常了。尝试一下管道运算符,会怎么样?

signature = conn  |> get_req_header("x-twilio-signature")|> List.first
if conn  |> url_from_conn|> Validator.validate(conn.params, signature)
do  conn
else  conn |> send_resp(401, "Not authorized") |> halt
end  

当你把管道运算符|>看成是goto的话,我们就能直观地体会到conn在各个函数中流动的现象了。非常可爱,不是吗?

Elixir是纯正的函数式语言,本质上讲,Elixir中的一切皆为函数,所以if表达式其实也是函数。这就意味着validate后的布尔结果可以通过|>直接传递给if:

signature = conn  |> get_req_header("x-twilio-signature")|> List.first
conn
|> url_from_conn
|> Validator.validate(conn.params, signature)
|> if(do: conn, else: conn |> send_resp(401, "Not authorized") |> halt)

这才是真正Elixir Style的编程范儿,够妩媚吧!

Joe Armstrong认为管道运算符来自Prolog语言的隐性基因DCG,类似Haskell中的monad。Prolog的儿子erlang没有体现这一点,孙子辈又隔代遗传上了。

工程支持

Elixir的创造者José Valim乃Rails的核心参与者,所以他把Rails社区(包括Ruby社区)中一套让人目眩的工程实践照般过来了。

脚手架

通过mix可以直接帮助我们创建项目的脚手架(用过rails的童鞋感到亲切了吗?):

mix new myproject

执行这条命令,mix就会帮我们创建项目的基本结构和相应文件:

包管理与依赖管理

通过Hex来管理包(记得GEM吗?)。在http://hex.pm中几乎可以找到所有你想要的elixir包;当然你还可以享受Erlang的福利,直接重用erlang包。

添加依赖也非常方便,只需要在项目的mix.exs文件中添加依赖即可。例如添加HTTPoison和JSX包的依赖:

  defp deps do[{:httpoison, "~> 0.11.0"},{:jsx, "~> 2.8"}]end

最棒的是,Elixir还支持直接对github repository的依赖。

环境配置

对开发环境、测试环境、生产环境的配置支持。在config目录下的config.exs文件中可以添加必要的配置项,还可以通过如下语句import不同环境的配置:

import_config "#{Mix.env}.exs"
单元测试

还有不能忘记的单元测试,这可是敏捷社区的随身法宝啊;Elixir通过内嵌的ExUnit很好地支持了单元测试的编写:

defmodule MyprojectTest douse ExUnit.Casedoctest Myprojecttest "sort ascending orders the correct way" doresult = sort_into_ascending_order(fake_created_at_list(["c", "a", "b"]))issues = for issue <- result, do: issue["created_at"]assert issues == ~w{a b c}end
end

如此简单。要运行所有测试,只需运行mix test即可。

其他

Elixir还有很多酷炫的玩意儿,例如Protocol、Behavior,当然还有最棒的(当然也可能是最令人费解的)宏(Macro)。Elixir对DSL的支持也非常友好,这来自它继承的部分Ruby血统。例如,让我们看看ECTO(一个基于Elixir开发的支持数据库访问的框架)的一段客户代码:

defmodule Sample.App doimport Ecto.Queryalias Sample.Weatheralias Sample.Repodef keyword_query doquery = from w in Weather,where: w.prcp > 0 or is_nil(w.prcp),select: wRepo.all(query)enddef pipe_query doWeather|> where(city: "Kraków")|> order_by(:temp_lo)|> limit(10)|> Repo.allend
end

因为没有大括号、括号以及分号的干扰,代码可以变得更接近领域逻辑,再加上性感的管道运算符,可读性直接爆表,帅呆了!

神奇的仙丹,性感的Elixir相关推荐

  1. 《Elixir in Action》书评及作者问答录

    <Elixir in Action>是由Manning所出版的一本新书,本书为读者介绍了Elixir这门语言以及Erlang虚拟机,同时也讨论了与并发编程.容错以及与高可用性相关的话题.I ...

  2. [elixir! #0023] 引擎盖下, `IO.puts` 如何运作

    `IO.puts "Hello world!" 接触elixir时, 学会的第一行代码是 IO.puts "Hello world!". 出于好奇, 我观察了一 ...

  3. Sublime Text 2 - 性感无比的代码编辑器!程序员必备神器!跨平台支持Win/Mac/Linux,支持32与64位,支持各种流行编程语言的语法高亮、代码补全等...

    Sublime Text 2 - 性感无比的代码编辑器!程序员必备神器!跨平台支持Win/Mac/Linux,支持32与64位,支持各种流行编程语言的语法高亮.代码补全等-- 语法高亮.代码提示补全. ...

  4. 干翻华为才有年终奖,“性感”小米发布MIX3,滑盖全面屏只要3299元

    Are you ok? 小米又发新机了! 这次发布会开到故宫了.虽然不知道故宫的花花草草和皇家御喵是不是米粉,但是正戏开始前还是先来一遍Are you ok清新洗脑一下吧! 话不多说,先前在8月份和O ...

  5. 90后创业者自述:不性感没逼格不能活

    90后创业者自述:性爱不是说说而是做,不性感没逼格不能活 文/崔大宝 [本文来自钛媒体特色栏目"创业者自述",自述成长的故事] 现如今90后创业也是屡见不鲜的事情,而真正能够成功的 ...

  6. 机器人二弟_“可佳二代”机器人好性感

    将本文分享到微博: 小观众认真观看机器人表演 "晨报读者这边走--"5月14日上午,在科大科技周各科普点,300余人的晨报"科技周"探秘团,在各分队志愿者导游带 ...

  7. Sublime Text 2 - 性感无比的代码编辑器

    Address: http://www.iplaysoft.com/sublimetext.html Sublime Text 2 - 性感无比的代码编辑器!程序员必备神器!跨平台支持Win/Mac/ ...

  8. Lua sublime Text 2 - 性感无比的代码编辑器!程序员必备神器!跨平台支持Win/Mac/Linux

    sublime Text 2 - 性感无比的代码编辑器!程序员必备神器!跨平台支持Win/Mac/Linux [  编程开发,  编辑输入 -  Windows,  Mac,  Linux // 20 ...

  9. 一段神奇的c代码错误分析

    源代码 #include <stdio.h>int main(int argc, char* argv[]) {int i = 0;int arr[3] = {0};printf(&quo ...

最新文章

  1. Confluence 6 有关空间的一些提示
  2. GPIO 输入—按键检测
  3. 破windows xp登陆密码
  4. 好听的歌曲---爱情转移
  5. SpringBoot整合Spring Security——登录管理
  6. Serializable接口中serialVersionUID字段的作用
  7. docker实战系列之搭建rabbitmq
  8. python 什么是序列_从零起步学Python——什么是序列?
  9. yield关键字有什么作用
  10. jQuery之.queue()
  11. 洛谷省选斗兽场全通关祭~以及之后的打算!
  12. android datepicker 监听,Android编程之DatePicker和TimePicke简单时间监听用法分析
  13. excel编写计算机台账,[一键生成excel表格]excel表格生成台账的方法
  14. 超市密码箱c语言程序,超市存包系统C语言.doc
  15. UItraEdit激活码
  16. China Joy 还没看够?2020 谷歌游戏出海峰会带来更多精彩!
  17. word怎么根据点画曲线_用word怎么画曲线图 word里如何绘制曲线图
  18. gitbook安装使用看完这一篇就够了
  19. 如何优化我的世界服务器,我的世界服务器怎么优化 服务器优化建议
  20. PHPExcel大文件导入数据库

热门文章

  1. linux没有c编译器,兄弟们,我这有台电脑里的Linux缺少cc(C编译器),我该怎么把它补上去啊?急啊!!!...
  2. 广义表头尾链表存储结构_详解Redis五种数据结构的底层原理
  3. oracle中累计求和_Excel中常见的7种求和公式
  4. Linux截图工具import使用说明
  5. 斯坦福2019强化学习课程完结,讲义、PPT、视频已提供下载
  6. 无人车创业正驶入分水岭
  7. 又一北大系AI公司浮出水面,百炼智能宣布获千万元天使投资
  8. 马库斯再谈AlphaGo Zero不是从零开始,AGI可能需要这十大先天机制
  9. 李开复:2018中国最大AI红利?是政策
  10. 当区块链遇到零知识证明 1