我以为 head 正在不断更新...
不。每次调用sum() 时都会创建一个新的、单独的head 变量。这是通过创建一个新的堆栈框架来实现的,其中一个框架包含函数调用创建的所有局部变量——包括像head这样的参数变量。
如果你这样写:
x = 3 + func1()
elixir 必须计算func1() 才能计算x 变量的值。并且,func1()的定义可能会创建自己的x变量,所以elixir会分配一个新的栈帧来计算func1()的返回值。一旦 elixir 计算出 func1() 的返回值,该值将代入上面的行:
42
|
V
x = 3 + func1()
x = 3 + 42
x = 45
...elixir 可以计算x 变量的值。
如果你写,同样的事情会发生:
4 + sum([5,6,7])
唯一的区别是elixir会在栈上分配很多栈帧来计算sum([5,6,7])的返回值。使用递归函数调用,每个堆栈帧的返回值将取决于另一个堆栈帧的返回值。只有当达到基本情况,并且sum([])返回0时,elixir才能开始在每个堆栈帧内填充所需的值以计算返回值。
4 + sum([5,6,7])
|
|
#1 V sum([5,6,7])
+--------------------+
| head = 5 |
| tail = [6,7] |
| |
| return: |
| head + sum(tail) |
| 5 + sum([6,7]) |
+-------------|------+
|
#2 V sum([6,7])
+----------------------+
| head = 6 |
| tail = [7] |
| |
| return: |
| head + sum(tail) |
| 6 + sum([7]) |
+-----------------|----+
|
#3 V sum([7])
+----------------------+
| head = 7 |
| tail = [] |
| |
| return: |
| head + sum(tail) |
| 7 + sum([]) |
+----------------|-----+
|
#4 V sum([])
+-----------------------+
| return: 0 |
+-----------------------+
请注意,同时存在三个独立的head 变量。一旦底部堆栈帧返回,就会启动以下步骤:
4 + sum([5,6,7])
^
|
+---18-----------<----------+
+--------------------+ |
| head = 5 | |
| tail = [6,7] | |
| | ^
| return: | |
| head + sum(tail) | |
| 5 + sum([6,7]) ---->---18-----+ #7
+-------------^------+
|
+--13------<----------+
+----------------------+ |
| head = 6 | |
| tail = [7] | |
| | ^
| return: | |
| head + sum(tail) | |
| 6 + sum([7]) -|-->--13--+ #6
+-----------------^----+
|
+---7--<-------+
+----------------------+ |
| head = 7 | ^
| tail = [] | |
| | |
| return: | ^
| head + sum(tail) | |
| 7 + sum([]) --|>--7-+
+----------------^-----+
|
+----0--<---+
+-----------------+ |
| return: 0 --|>--0-+ #5
+-----------------+
如果您在代码中添加一些打印语句,您可以看到这些步骤是如何执行的:
defmodule My do
def sum([]) do
IO.puts("Inside sum([]):\n\treturning 0")
0
end
def sum([head | tail]) do
IO.puts("Inside sum([head|tail]), head=#{head} tail=#{inspect(tail, charlists: :as_lists)}")
val = head + sum(tail)
IO.puts("Inside sum([head|tail]), head=#{head} tail=#{inspect(tail, charlists: :as_lists)}")
IO.puts("\treturning #{val}")
val
end
end
My.sum([5,6,7])
在命令行:
~/elixir_programs$ elixir a.exs
Inside sum([head|tail]), head=5 tail=[6, 7]
Inside sum([head|tail]), head=6 tail=[7]
Inside sum([head|tail]), head=7 tail=[]
Inside sum([]):
returning 0
Inside sum([head|tail]), head=7 tail=[]
returning 7
Inside sum([head|tail]), head=6 tail=[7]
returning 13
Inside sum([head|tail]), head=5 tail=[6, 7]
returning 18