模式匹配
作为与erlang
一脉相承的语言,elixir
自然继承了erlang
的模式匹配思想,所以在elixir
中,等号虽然也可以起到赋值的作用,但实质是匹配操作符。和赋值号相比,模式匹配并不要求左边的一定是变量
> x = 1
1
> 1 = x
1
> 2 = x
** (MatchError) no match of right hand side value: 1
(stdlib 4.3.1) erl_eval.erl:496: :erl_eval.expr/6
iex:9: (file)
但与erlang
不同,elixir
支持变量的重新绑定,也就是说,当已经对x
进行赋值之后,若在此基础上使用x=2
,则可能出现两个含义,一是做匹配,二是重新匹配,也就是重新赋值。
为了避免这个问题,elixir
提供了定位操作符^
> ^x=2 # 对x和2进行匹配,显然没匹配成功
** (MatchError) no match of right hand side value: 2
(stdlib 4.3.1) erl_eval.erl:496: :erl_eval.expr/6
iex:9: (file)
> x = 2 # 对x重新绑定为2
2
case
elixir
的流程控制思路与erlang
相同,都是主打case
,且不支持循环,若非想要循环,那就得通过递归实现。
case
是一种匹配筛选机制,与elixir
的模式匹配思想十分契合,其基本语法是
case ... do
aaa ->
bbb ->
end
下面在模块中新建一个函数,
# Test.ex
defmodule Test do
def caseTest(num) do
case num do
1 -> "you input 1"
2 -> "you input 2"
_ -> "you didn't input 1 or 2"
end
end
end
测试结果如下
>iex Test.ex
iex(1)> Test.caseTest(1)
"you input 1"
iex(2)> Test.caseTest(2)
"you input 2"
iex(3)> Test.caseTest(3)
"you didn't input 1 or 2"
cond
case
的特点是只能匹配静态的内容,而无法在匹配表达式的结果,cond
弥补了这一不足,可以在匹配条件中输入表达式。下面在Test
模块中测试一下cond
def condTest(x) do
cond do
x*x < 10 -> "#{x}^2<10"
x*x < 100 and x*x >= 10 -> "#{x}^2 in [10, 100)"
x*x > 100 -> "#{x}^2 > 100"
end
end
测试一下
iex(1)> Test.condTest(20)
"20^2 > 100"
cond
不仅是case
的一种更灵活的替代,同时可以对标其他语言中的if..else if
语句,从而支持多种条件的判断。
键值对类型
elixir
中提供了关键字列表、表单以及字典这几种键值对类型,所谓键值对,就是通过key
来索引对应value
的数据结构,其调用思路与case
的逻辑是相似的,只不过case
是根据匹配内容,执行某个表达式,而键值对则是根据匹配内容,返回对应的值而已。
关键字列表示例如下
> lst = [{:a, 0x61}, {:b, 0x62}, {:c, 0x63}]
[a: 97, b: 98, c: 99]
> lst[:a]
97
即每个{}
中都是一组键值对,且键必须是原子。
表单相对来说更加灵活,至少支持任意类型的键,示例如下
> map = %{"a"=>0x61, "b"=>0x62}
%{"a" => 97, "b" => 98}
> map["a"]
97
可见,其语法格式与关键字列表不同,所有的键值对都在%{}
中,键值之间的映射关系,通过符号=>
来完成。
在elixir
中,关键字列表和表单都可以理解为字典的特殊表现形式,在字典模块Dict
中封装了一系列用于表单和关键字列表的函数。由于本文主要介绍elixir
的模式匹配思想,故而这些案例将在后面再行讲解。