我在Elixir中创建了一个简单的函数,该函数将元组的值加1。
我将模块命名为Test,并将函数命名为addToTuple。它有一个参数,就是元组本身。
def addToTuple({X,Y}) do
{X,Y+1}
end
我通过iex编译了模块,并收到以下警告:
warning: this expression will fail with ArithmeticError
Test.ex:68
第68行引用{X,Y + 1}。当我使用命令Test.addToTuple({4,5})运行该函数时,我不断收到此错误:
** (FunctionClauseError) no function clause matching in Test.addToTuple/1
The following arguments were given to Test.addToTuple/1:
# 1
{4, 5}
Test.ex:67: Test.addToTuple/1
我原本希望得到{4,6}。
你知道这是怎么回事吗?
更新1:
我将X和Y更改为小写,并且有效。但是,这次我对函数进行了一些修改以与原子配合使用:
def addToTuple({A,x,y}) do
{A,x,y+1}
end
然后我使用以下命令调用该函数:Test.addToTuple({:F,4,5})。我期待得到{:F,4,6}。但是,相反,我得到了这个错误:
** (FunctionClauseError) no function clause matching in Test.addToTuple/1
The following arguments were given to Test.addToTuple/1:
# 1
{:F, 4, 5}
Test.ex:67: Test.addToTuple/1
我认为使用大写字符会被视为原子?该如何解决?
答案 0 :(得分:5)
在此处的函数定义中:
def addToTuple({A,x,y})
A
不是变量,而A
是原子,就像一个常数。通常,您这样编写原子:
:dog
:"my dog"
但是,还有另一种用于创建原子的语法:您可以省略前导冒号并以大写字母开头,例如:
Dog
Elixir in Action(2nd)称为 别名 (对于原子)。在编译时,Dog
被转换为原子:"Elixir.Dog"
。检查一下:
iex(5)> Dog == :"Elixir.Dog"
true
返回您的函数定义:
def addToTuple({A,x,y})
唯一与您的函数定义匹配的参数如下:
{A, 1, 3}
{A, "hello", "world"}
{A, [1, 2, 3], [4, 5, 6]}
换句话说,将与功能参数列表中的A
“匹配”的唯一事物是A
。 Elixir与其他语言不同,在其他语言中,函数定义的参数列表中仅允许变量。在其他语言中,函数定义如下所示:
def go(x, y, z) do
...
end
但是,在elixir中,您可以在参数列表的参数列表中包含 常数 ,如下所示:
def go(1, x, 2, y) do
...
end
在该函数定义中,参数包括常量1
和2
。如果您这样调用该函数:
go(10, 20, 30, 40)
该函数将不会执行,因为函数参数10, 20, 30, 40
与函数参数1, x, 2, y
不匹配。调用函数时,函数参数将与函数参数匹配,如下所示:
go(10, 20, 30, 40)
| | | |
V V V V
def go(1, x, 2, y) do
对于该函数调用,elixir执行以下匹配/分配:
1 = 10
x = 20
2 = 30
y = 40
由于1与10不匹配,因此该功能无法执行。原子A
就像整数1和2一样。唯一匹配A
的是A
。
由于elixir允许在函数的参数列表中使用常量,因此您可以定义一系列函数子句,如下所示:
defmodule My do
def go(1, x) do
IO.puts x*2
end
def go(2, x) do
IO.puts x-4
end
def go(A, x) do
IO.puts x+5
end
end
My.go(2, 3)
My.go(A, 5)
输出:
-1
10
当您调用定义了多个子句的函数时,elixir从第一个子句开始,并尝试将函数调用中的参数与参数列表进行匹配。如果没有匹配项,则elixir尝试下一个函数子句,依此类推。找到匹配项后,将执行该函数子句。如果找不到匹配项,则长生不老药将引发错误。例如,调用:
My.go(B, 3)
导致:
** (FunctionClauseError) no function clause matching in My.go/2
另一个例子:
defmodule My do
def calc({:add, x, y}) do
x + y
end
def calc({:subtract, x, y}) do
x - y
end
def calc({:multiply, x, y}) do
x * y
end
end
在iex中:
~/elixir_programs$ iex my.exs
Erlang/OTP 20 [erts-9.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]
Interactive Elixir (1.6.6) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> My.calc {:add, 10, 5}
15
iex(2)> My.calc {:subtract, 10, 5}
5
iex(3)> My.calc {:multiply, 10, 5}
50