Elixir 编程Elixir & Phoenix程序员

Elixir学习笔记(基本操作、Enum板块)

2018-04-11  本文已影响86人  程序员小哥哥

基本操作

算数运算

Elixir 支持基本的 +-*/操作符,不过要注意 / 的结果是浮点数。

iex(1)> 1 + 1
2
iex(2)> 2 - 1
1
iex(3)> 2 * 5
10
iex(4)> 10 / 2
5.0

10 / 2返回了一个浮点型的5.0而非整型的5,这是因为在Elixir中,/运算符总是返回浮点型数值。
如果你需要整数除法和求余,Elixir 提供了两个函数:

iex(5)> div(10, 2)
5
iex(6)> rem(10, 3) #rem的意思是division remainder,余数的意思
1
iex(7)> rem 10, 3 #在写函数参数的时候,括号是可选的
1

Elixir还提供了++--运算符来操作列表:

iex(1)> [1, 2, 3] ++ [4, 5, 6]
[1, 2, 3, 4, 5, 6]
iex(2)> [1, 2, 3] -- [2]
[1, 3]

Elixir还提供了三个布尔运算符:orandnot。这三个运算符只接受布尔值作为 第一个 参数:

iex(3)> true and true
true
iex(4)> false or is_atom(:example)
true

如果提供了非布尔值作为第一个参数,会报异常:

iex(5)> 1 and true
** (BadBooleanError) expected a boolean on left-side of "and", got: 1

除了这几个布尔运算符,Elixir还提供||&&!运算符。它们可以接受任意类型的参数值。 在使用这些运算符时,除了 false 和 nil 的值都被视作 true:

# or
iex(5)> 1 || true
1
iex(6)> false || 2
2

# and
iex(7)> nil && 11
nil
iex(8)> true && 22
22

# !
iex(9)> !true
false
iex(10)> !1
false
iex(11)> !nil
true

当参数确定是布尔时,使用and,or和not; 如果非布尔值(或不确定是不是),用&&||!

字符串拼接

使用 <> 操作符进行字符串拼接:

iex(17)> name = "Elixir"
"Elixir"
iex(18)> "hello " <> name
"hello Elixir"

比较运算符

Elixir 有我们习惯的一切比较运算符 :==, !=, ===, !==, <=, >=, < 和 >

iex(7)> 1 > 1
false
iex(8)> 1 != 1
false
iex(9)> 1 == 1
true
iex(10)> 2 <= 3
true

对于整数和浮点数的严格比较,可以使用 ===

iex(11)> 2 == 2.0
true
iex(12)> 2 === 2.0
false

在Elixir中,可以判断不同类型数据的大小:

iex(12)> 1 < :atom
true

这很实用。排序算法不必担心如何处理不同类型的数据。总体上,不同类型的排序顺序是:

number < atom < reference < functions < port < pid < tuple < maps < list < bitstring

字符串插值

如果你使用过 Ruby,那么 Elixir 的字符串插值看起来会很熟悉:

iex(13)> name = "Elixir"
"Elixir"
iex(14)> "I love #{name}"
"I love Elixir"

Enum板块

Enum

Enum 模块提供了超过一百个函数.
这节我们只会覆盖一部分函数,不过我们随时都可以自己去了解。 让我们在 IEx 里做个小试验

iex
iex> Enum.__info__(:functions) |> Enum.each(fn({function, arity}) ->
...>   IO.puts "#{function}/#{arity}"
...> end)
all?/1
all?/2
any?/1
any?/2
at/2
at/3
...

通过上面的命令,很明显能看到我们有很多函数,而且这些函数都是师出有名。
集合在函数式编程中处于核心地位,同时也是非常有用的部分。
通过利用它与Elixir的其他优势相结合,比如我们刚看到的,文档是一等公民,可以赋予开发人员非常强大的能力。
要想了解全部的函数,请访问官方的 Enum 文档。而要想了解惰性枚举(lazy enumeration),访问 Stream 模块。

all?

使用all?以及大部分Enum函数的时候,我们要提供一个函数来作用到要操作的集合上。
只有当函数在所有的元素上都返回true的时候,all? 才会返回true,否则结果就是false

iex(13)> Enum.all?(["foo", "bar", "hello"], fn(s) -> String.length(s) == 3 end)
false
iex(14)> Enum.all?(["foo", "bar", "hello"], fn(s) -> String.length(s) > 1 end)
true

any?

和上面不同,只要有一个元素被函数调用返回trueany?就会返回true

iex(15)> Enum.any?(["foo", "bar", "hello"], fn(s) -> String.length(s) == 5 end)
true

chunk_every/2

如果你想把你的集合拆分成小的分组,chunk_every/2就是你要找的函数:

iex(16)> Enum.chunk_every([1, 2, 3, 4, 5, 6], 2)
[[1, 2], [3, 4], [5, 6]]

chunk_every/2 还有其他选项,在这里不深入介绍。如果感兴趣,前往 chunk_every/4 的官方文档去了解

chunk_by

如果不按照数量分组(每组的元素数量相同),我们可以使用 chunk_by 方法。
它接受一个枚举值和一个函数作为参数,如果函数的返回值变了,就是从新从后开始分组 :

iex(17)> Enum.chunk_by(["one", "two", "three", "four", "five"], fn(x) -> String.length(x) end)
[["one", "two"], ["three"], ["four", "five"]]
iex(18)> Enum.chunk_by(["one", "two", "three", "four", "five", "six"], fn(x) -> String.length(x) end)
[["one", "two"], ["three"], ["four", "five"], ["six"]]

map_every

有时候把集合分组并不能满足我们的需求。这时候 map_every/3 在修改集合中特定元素的时候会非常有用:

iex(19)> Enum.map_every([1, 2, 3, 4], 2, fn x -> x * 2 end)
[2, 2, 6, 4]

each

有时候需要遍历某个集合进行操作,但是不想产生新的值(不把函数的遍历调用结果返回),这种情况下,可以使用each

iex(20)> Enum.each(["one", "two", "three"], fn(s) -> IO.puts(s) end)
one
two
three
:ok

注意:each函数会返回原子:ok

map

要把某个元素都执行某个函数,并且把结果作为新的集合返回,要使用 map 函数:

iex(21)> Enum.map([0, 1, 2, 3], fn(x) -> x - 1 end)
[-1, 0, 1, 2]

min

min/1在集合中找到最小的值:

iex(22)> Enum.min([5, 3, 0, -1])
-1

min/2也一样,但是它允许我们提供一个匿名函数指定计算最小值的方法:

iex(23)> Enum.min([], fn -> :foo end)
:foo

max

max/1 返回集合中最大的值:

iex(24)> Enum.max([5, 3, 0, -1])
5

max/2也一样,而且像min/2一样,它允许我们提供一个匿名函数指定计算最大值的方法:

iex(25)> Enum.max([], fn -> :bar end)
:bar

reduce

使用reduce,我们可以把集合不断计算,最终得到一个值。我们需要提供一个可选的累加值(在这个例子中是 10),
如果没有累加值,集合中的第一个值会被使用。

iex(26)> Enum.reduce([1, 2, 3], 10, fn(x, acc) -> x + acc end)
16
iex(27)> Enum.reduce([1, 2, 3], fn(x, acc) -> x + acc end)
6
iex(28)> Enum.reduce(["a","b","c"], "1", fn(x,acc)-> x <> acc end)
"cba1"

sort

对集合进行排序,Elixir 提供了两个sort函数来帮忙。第一个使用 Elixir 默认的排序规则进行排序:

iex(29)> Enum.sort([5, 6, 1, 3, -1, 4])
[-1, 1, 3, 4, 5, 6]
iex(30)> Enum.sort([:foo, "bar", Enum, -1, 4])
[-1, 4, Enum, :foo, "bar"]

另外sort允许我们自己提供排序函数:

# with our function
iex(31)> Enum.sort([%{:val => 4}, %{:val => 1}], fn(x, y) -> x[:val] > y[:val] end)
[%{val: 4}, %{val: 1}]
# without
iex(32)> Enum.sort([%{:count => 4}, %{:count => 1}])
[%{count: 1}, %{count: 4}]

uniq_by

我们可以使用 uniq_by/2删除集合中的重复元素:

iex(33)> Enum.uniq_by([1, 2, 3, 2, 1, 1, 1, 1, 1], fn x -> x end)
[1, 2, 3]

这跟我们以前都熟悉的uniq/1函数一样,但是这个函数在 Elixir 1.4 中被弃用,不过你还是可以使用它(会收到一个警告信息)。

上一篇下一篇

猜你喜欢

热点阅读