elixir语言精髓:模式匹配

模式匹配

作为与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的模式匹配思想,故而这些案例将在后面再行讲解。

猜你喜欢

转载自blog.csdn.net/m0_37816922/article/details/130925444