immutability - Elixir 变量真的是不可变的吗?

标签 immutability elixir

在 Dave Thomas 的《Programming Elixir》一书中,他指出“Elixir 强制执行不可变数据”,并接着说道:

In Elixir, once a variable references a list such as [1,2,3], you know it will always reference those same values (until you rebind the variable).

这听起来像是“除非你改变它,否则它永远不会改变”,所以我对可变性和重新绑定(bind)之间的区别感到困惑。一个突出差异的例子会非常有帮助。

最佳答案

不要将 Elixir 中的“变量”视为命令式语言中的变量、“值的空间”。而是将它们视为“值(value)标签”。

当您了解变量(“标签”)在 Erlang 中的工作原理时,也许您会更好地理解它。每当您将“标签”绑定(bind)到某个值时,它就会永远与其绑定(bind)(范围规则当然适用于此处)。

在 Erlang 中你不能这样写:

v = 1,      % value "1" is now "labelled" "v"
            % wherever you write "1", you can write "v" and vice versa
            % the "label" and its value are interchangeable

v = v+1,    % you can not change the label (rebind it)
v = v*10,   % you can not change the label (rebind it)

相反,你必须这样写:

v1 = 1,       % value "1" is now labelled "v1"
v2 = v1+1,    % value "2" is now labelled "v2"
v3 = v2*10,   % value "20" is now labelled "v3"

正如你所看到的,这非常不方便,主要是为了代码重构。如果您想在第一行之后插入新行,则必须重新编号所有 v* 或编写类似“v1a = ...”的内容

所以在Elixir中你可以重新绑定(bind)变量(改变“标签”的含义),主要是为了你的方便:

v = 1       # value "1" is now labelled "v"
v = v+1     # label "v" is changed: now "2" is labelled "v"
v = v*10    # value "20" is now labelled "v"

摘要:在命令式语言中,变量就像命名的手提箱:您有一个名为“v”的手提箱。首先你把三明治放进去。比你在里面放一个苹果(三明治丢失了,可能被垃圾收集器吃掉了)。在 Erlang 和 Elixir 中,变量不是放置内容的地方。它只是值的名称/标签。在 Elixir 中,您可以更改标签的含义。在 Erlang 中你不能。 这就是为什么在 Erlang 或 Elixir 中“为变量分配内存”没有意义的原因,因为变量不占用空间。值(value)观确实如此。现在也许您清楚地看到了差异。

如果你想深入挖掘:

1) 看看“未绑定(bind)”和“绑定(bind)”变量在 Prolog 中如何工作。这就是 Erlang 中“不变的变量”这个可能有点奇怪的概念的来源。

2) 请注意,Erlang 中的“=”实际上不是一个赋值运算符,它只是一个匹配运算符!当将未绑定(bind)变量与值匹配时,将该变量绑定(bind)到该值。匹配绑定(bind)变量就像匹配它所绑定(bind)的值一样。所以这会产生一个匹配错误:

v = 1,
v = 2,   % in fact this is matching: 1 = 2

3) Elixir 中并非如此。所以在 Elixir 中必须有一个特殊的语法来强制匹配:

v = 1
v = 2   # rebinding variable to 2
^v = 3  # matching: 2 = 3 -> error

关于immutability - Elixir 变量真的是不可变的吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29967086/

相关文章:

swift - 不可变的 `var` 数组

concurrency - Elixir/Erlang 和 Cowboy - 如何使用主管

灵药/Phoenix : Why do route helpers require @conn?

elixir - Elixir 的 Ecto : Foreign Key

elixir - 分离进程不写入文件 & rpc 调用因连接节点错误而失败

java - 注释如何防止数组参数的突变?

java - 为什么字符串在许多编程语言中都是不可变的?

clojure - 在我自己的数据结构中递增数字时 clojure 中的不变性,从常见的 lisp 可变性到 clojure 不变性

java - Java中可变对象的封装

Elixir 将 header 字符串转换为映射