編程語言有了基本數據結構,那么可以遣詞造句了。等等,詞組是有了,可是如何把這些詞組組合起來呢?
本節將會介紹運算符,基本數據結構通過運算符的計算,獲得預期的值。Elixir的運算符與其他語言類似,并沒有特別之處。主要有下面幾類:
- 布爾操作符 (Boolean operators)
- 比較操作符 (Comparison operators)
- 算術運算符(Arithmetic operators)
- 包含操作符(in operator)
布爾操作符
Elixir的布爾操作符只有三個,分別是and
,or
,not
。之前介紹了布爾類型的數據結構。布爾操作符恰恰就是專門用于操作布爾類型的操作符。并且,布爾操作符只能接受布爾值做運算,非布爾值將會報錯。
iex(1)> a = true
true
iex(2)> b = false
false
iex(3)> a and b
false
iex(4)> a or b
true
iex(5)> not a
false
iex(6)> not 1
** (ArgumentError) argument error
:erlang.not(1)
iex(6)> 1 and 2
** (ArgumentError) argument error: 1
iex(6)> 2 or 3
** (ArgumentError) argument error: 2
布爾操作符運算遵循短路規則。即and表達式總是返回第一個false,如果全部是true的值,則返回最后一個true的值。or則返回第一個是true的值,如果都是false,則返回最后一個false的值。not則最簡單,取反的值即可。一旦表達式返回了,就不會計算后面的邏輯表達式了。
and
a and b # 如果 a 的值是 false,返回false,否則返回 b
iex(1)> a = false
false
iex(2)> b = 1
1
iex(3)> a and b
false
iex(4)> a = true
true
iex(5)> a and b
1
這里需要注意,方才我們說布爾操作符只接受布爾值,非布爾值將會報錯。為什么當 a=true
,b=1
的時候,a and b
不會報錯,反而返回b的值呢?
實際上,上面的and操作符運算的時候,都是從左往右計算求值,對于表達式 a and b
。可以這么理解,and 的左邊對a求值得到true(a=true變量綁定)。然后and操作符左邊接受且必須接受一個布爾值,此時為a,根據and的計算原則,如果a的true,直接返回。如果a的false,則不需要計算后面的結構了,直接返回and右邊的b。也就是說b并沒有被and計算求值。
在看下面的表達式:
iex(6)> a and b and b
** (ArgumentError) argument error: 1
iex(6)> a and b and 1
** (ArgumentError) argument error: 1
在第一個b后面再使用and操作符,第一個and把a當成參數計算的結果是返回b,第二個and則把返回的b當成自己的參數進行計算,顯然此時b為1,不是布爾值,因此第二個and操作符報錯。
iex(8)> a and true and b
1
iex(9)> a and true and a and b
1
當and計算到最后一個元素,都是true的時候,則直接返回最后一個元素。例如上面的例子,最后一個and前面的值都是true,則返回and右邊的值,此時不需要對右邊的值進行邏輯求值。
掌握邏輯操作的關鍵就是布爾操作符號每次只把左邊的數當成參數求值計算,要么返回計算的結果,要么就返回右邊的值。此時右邊的值無需計算。
or
or操作符的原則是
a or b # 如果 a 的值是 true,返回ture,否則返回 b
iex(1)> a = true
true
iex(2)> a or b
true
iex(3)> b = 1
1
iex(4)> a = false
false
iex(5)> a or b
1
iex(6)> a or b or true
** (ArgumentError) argument error: 1
掌握了邏輯運算的規則,or也很容易理解。or左邊是true,則返回true,如果左邊不是true,則直接返回右邊的值,不需要對右邊的項求值,除非右邊的項右邊還有操作符。
not
not操作符最簡單了
not a # 如果 a 的值是 true,返回false,否則返回 true
與and,or 不同的在于,not不是對左邊的項求值,而是對右邊的第一項求值。
下面看一個表達式,你覺得結果是什么呢?為什么?
iex(2)> me = true
true
iex(3)> you = false
false
iex(4)> him = :love_u
:love_u
iex(5)> me and you or him
???
當然,如果覺得邏輯操作符只能對布爾值求值比較麻煩。想要對普通的類型求值,可以使用寬松的邏輯操作符&&
, ||
,!
。這三個符號也可以做布爾運算,并且可以接受非布爾值做計算。其中計算的原則是,除了false和nil兩個值之外,其他的一切類型求值都是true。
iex(1)> a = true
true
iex(2)> b = 1
1
iex(3)> a and b
1
iex(4)> a and b and 1
** (ArgumentError) argument error: 1
iex(4)> a && b
1
iex(5)> a && b && 1
1
iex(6)> nil && a
nil
iex(7)>
||
和!
與or和not類似,大家可以自己試試。
比較操作符
Elixir中的=
表示模式匹配的符號,與其他語言不一樣。那么其他語言的雙等號==
,Elixir也別有洞天么?
當然不是Elixir的==
與其他語言基本一樣,用于表示==
符號左右兩邊的數值相當。但是,僅僅是表示值相等,如果需要表示值和類型都相等,需要再加一個等號。
iex(1)> a = 1
1
iex(2)> b = 1.0
1.0
iex(3)> a == b
true
iex(4)> a === b
false
iex(5)>
比較操作符也沒有什么特別的,大致如下:
a === b # 嚴格意義上的相等,包括值和數據類型 (so 1 === 1.0 is false)
a !== b # 嚴格意義上的不等 (so 1 !== 1.0 is true)
a == b # 值相等 (so 1 == 1.0 is true)
a != b # 值不等 (so 1 != 1.0 is false)
a > b # 大于
a >= b # 大于等于:
a < b # 小于:
a <= b # 小于等于:
比較操作符除了做數值大小的比較,還可以做排序的比較。Elixir中的比較排序并不像別的語言那么嚴格。不同類型也可以進行比較。如果類型相同或者一致,就會使用正常的類型比較。如果類型不同,則基于下面的優先原則:
數字類型(number) < 原子(atom) < 引用(reference) < 函數(function) < 端口(port) < 進程(pid) < 元組(tuple) < 圖(map) < 列表(list) < 二進制(binary)
算術運算符
算術運算符也很常見了,基本上就是四則運算符號。四個符號如下:
- 加法
- 減法
- 乘法
- / 除法
需要注意/
做除法的時候,得到的結果都是浮點型的,即使能運算能夠除盡。想要得到整型結果,需要使用內建的運算函數div
。div
的參數不能接受浮點型。Elixir很奇怪,沒有常見的%
做取余,而是使用一個內建的函數rem
。
iex(1)> 10 / 3
3.3333333333333335
iex(2)> 10 / 2
5.0
iex(3)> div 10, 3
3
iex(4)> div 10, 2
5
iex(5)> rem 10 , 3
1
iex(6)> div 10.0, 2
** (ArithmeticError) bad argument in arithmetic expression
:erlang.div(10.0, 2)
拼接操作(Join operators)
相信很多開發者都知道,+符號除了用于數字運算,還通常用于字符串數組列表等數據結構的拼接。elixir中提供了<>
拼接字符串,++
用于拼接列表,甚至還有--
用于列表相減。
包含操作符(in operator)
in
成員判斷操作符也很常用。用于判斷一個元素是否在一個容器集合里面。
本節針對elixir的基本運算符和操作符做了簡單的介紹。有了他們,配合強大的元組列表圖等結構。對于寫一個Elixir程序,已經差不多萬事俱備了。