Elixir,中文可以翻译为“灵丹妙药”。一门运行在 Erlang 虚拟机上的新语言,称自己为灵丹妙药,可见其霸气。Elixir 尝鲜之后,发现确实是一门博采众长的新语言。下面进行 Elixir 的简单介绍。
安装 Elixr
安装 elixir 相当方便,官方文档给出了不同平台的方法。由于 elixir 是运行在 erlang 虚拟机上的,因此需要安装 erlang。下面介绍在 MacOS 下的安装方法。如果有 homebrew,安装只需要两条命令。
-
安装 erlang
brew install erlang
-
安装 elixir
brew install elixir
打开 Terminal, 输入
elixir -v
可以获取安装的版本号,目前最新的是 1.0.2版本
Hello World
Elixir 自带了一个交互解释器,就像Python那样可以直接输入代码就执行,也类似 Ruby 的IRB。这个交互解释器为 IEX
。在 Terminal里面直接输入 iex,就可以进入elixir交互环境,按住control+z
退出,或者连续安两次control+c
。
进入 iex,会看到下面的样式:
Erlang/OTP 17 [erts-6.3] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]
Interactive Elixir (1.0.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)>
输入 "Hello World"
, elixir 用双引号来表示字符串。
> "Hello world"
"Hello world"
>
可以用 <>
连接字符串
> "hello" <> " " <> "elixir"
"hello elixir"
>
字符串支持多行,敲回车就可以跳下一行,直到遇到结束的双引号。不需要在前面留白,相当赞的功能。
> "I
> like
> elixir"
"I\nlike\nelixir"
>
基本运算
计算机本来就是用来做计算的,elixir当然也可以做计算,以及定义函数运算。elixir支持常见的数学运算。
> 1 + 1
2
> 2 * 3
6
> 10 / 2
5.0
> 10 / 3
3.3333333333333335
> 10 / 3.0
3.3333333333333335
> 3 * (1 + 2)
9
注意,elixir的除法总是返回浮点类型,例如上面的 10 / 2
返回的是 5.0
而不是5
。如果你想进行整型除法,或者求余数,可以使用div
和rem
函数。elixir的函数调用时候的括号是可以省略的,毕竟语言的作者是 rails 的核心成员,具有浓厚的 ruby 风格。
> div(10, 2)
5
> rem 10, 3
1
匿名函数
elixir 可以定义匿名函数,并且匿名函数可以匹配某个变量,通过变量调用匿名函数。定义匿名函数的关键字是 fn
和 end
。
> sum = fn x, y -> x + y end
#Function<12.90072148/2 in :erl_eval.expr/5>
> sum.(10, 9)
19
elixir是函数式范式编程语言,函数贵为一等公民。既可以直接调用,也可以当参数传入。匿名函数是闭包,因此它们可以访问当前作用域(scope)内的其它变量。并且elixir也可以定义像js那种立即执行的匿名函数
> x = 9
> (fn x -> x + 1 end).(x)
10
> x
9
基本数据类型
前面我们尝试了elixir的简单例子,其中发现了=
这个符号,在数学里这个是等号,表示左右两边相当,学过编程的人都知道,程序里的=
不是等号,而是赋值
号,指把右边的表达式或数值赋给左边的变量。elixir
与别的语言不一样,=
不能称之为赋值号,而是匹配运算符
,elixir称之为模式匹配
(pattern match)。后面我们再做解释。
前面我们见识了elixir的基本数据类型中的数字相关的类型。elixir的基本数据类型包括下面的几种:
- 布尔(boolean)
- 数字(number)
- 整型(integer)
- 浮点(float)
- 原子(atom)
- 字符串(string)
- 匿名函数(anonymous function)
- 列表(list)
- 元组(tuple)
布尔类型
elixir 用 true
和false
来表示布尔类型。对于判断类型,python提供了一个 type函数相当方便,可惜elixir并没有这样的type函数。不过elixir提供了不同的函数,用来判断类型,例如判断是否是布尔类型的is_boolean
函数。
> is_boolean(true)
true
> is_boolean(false)
true
> is_boolean(1)
false
> is_number(1)
true
注意,1 是数字类型,并不是布尔类型,当然在条件判断的时候,1 可以布尔值可以是true。后面会提到。
函数表示方法
elixir的文档工作做得也很好,对于语言的概念的描述和应用,也有自己的一套。例如函数的描述方法通常为 `<函数名>/<元数>`(<function name>/<arity>)。上面的判断类型函数可以描述为 `is_boolean/1`, `is_number/1`。元数可以理解为函数的参数。这个描述的好处在于,可以用帮助函数 `h` 来查看一个函数的文档和使用方法。类似python里的 `help` 函数。
使用 h 查看 is_boolean/1。
> h is_boolean
def is_boolean(term)
Returns true if term is either the atom true or the atom false (i.e. aboolean); otherwise returns false.
Allowed in guard tests. Inlined by the compiler.
>
配合模块的文档和函数的文档,能过构建文档完善的程序,这一点充分借鉴了Python的文档字符串设计。
原子
原子
(atom)是一种常量,变量名就是它的值。ruby、lisp 中称其为符号
(symbol)。定义十分简单,只需要在字符前加上:
符号。
> :atom
:atom
> :hello
:hello
> :123
** (SyntaxError) iex:29: invalid token: :123
注意,大写字母开头的"变量",其实是一种原子,是:Elixir.变量名
的别名。模块通常是用大小字母开头的,后面会用到。
> Hello
Hello
> Hello == :hello
false
> Hello == :Elixir.Hello
true
列表
列表是常用的数据类型,很多语言都支持列表或者数组的结构。elixir的列表稍微有点不同。
列表的声明可以使用一对方括号[]
,列表的元素可以是任意的数据类型。通过++
或者--
可以拼接列表和消除列表
> list = [1, 2, true, 3]
[1, 2, true, 3]
> [1, 2, 3] ++ [4, 5, 6]
[1, 2, 3, 4, 5, 6]
> [1, 2, 3, 11, 22, 33, 33, 22, 11] -- [11, 22, 33]
[1, 2, 3, 33, 22, 11]
列表相减的时候,是按照元素位置进行匹配的。想要获取列表的长度,也就是元素的个数,可以通过函数 lenght
得到,通过 hd
函数,可以获得列表的第一个元素,tl
函数则获取除第一个元素的剩余列表元素。这个操作在递归的时候很有用。当列表为空的时候,hd 和 tl 都会报错。
> list = [1, 2, 3, 4]
[1, 2, 3, 4]
> length list
4
> hd list
1
> tl list
[2, 3, 4]
列表在内存中是以链表的形式存储的,一个元素指向下一个元素,然后再下一个...直到到达列表末尾。我们称这样的一对(元素值+指向下一个元素的指针)为列表的一个单元(cons cell)。 由于列表的存储结构,获取列表的元素,都需要遍历列表,获取列表的长度是一个线性操作。我们必须遍历完整个列表才能知道它的长度而给列表删除和插入元素则相当高效。
|
这个操作符可以拼接列表,指在列表前置一个列表。事实上,列表的定义,就是单个列表元素拼接起来的,写出中括号的方式只是语法糖罢了。
> list = [3, 4, 5]
[3, 4, 5]
> [3| [4| [5| []]]]
[3, 4, 5]
> [1 | list]
[1, 3, 4, 5]
> [[1, 2] | list]
[[1, 2], 3, 4, 5]
> [1, 2 | list]
[1, 2, 3, 4, 5]
> list = [3|[]]
元组
elixir 的列表是链式存储的,而元组则是连续存储的,因此可以通过所以的方式访问元组。当然,修改元组,比如插入删除元素则开销很大。元组的作用很大,通过用来存储一些不容易变的数据。
元组的声明很简单,只需要一对花括号{}
,里面的类型也可以是任意类型。可以用 elem
函数和索引访问元组。
> t = {1, :ok, "hello"}
{1, :ok, "hello"}
> elem t, 1
:ok
更多的元组操作,会在后面的内容提及。
字符列表
字符串是用双引号定义的,单引号则定义的是字符串列表,可以使用列表的一些函数操作。
> 'hello'
'hello'
> list_str = 'hello'
'hello'
> is_list list_str
true
> 'hello' ++ 'world'
'helloworld'
Enjoy Elixir
这样就把elixir的基本东西快速瞥了一遍。具体每个数据类型的深入了解和运用,以及强大的函数、模块、宏等概念将会陆续介绍。
学习Elixir的时候,收获最大的则是《Elixir Programe》这本书。并且也按照自己的理解做了一些基础的翻译(github地址),这些笔记就是在翻译学习之后自己的总结。有兴趣的童鞋可以参考,或者帮忙修正。