目前正试图了解Elixir中的"^"运算符.来自网站:
当没有兴趣重新绑定变量而是匹配匹配之前的值时,可以使用pin运算符^:
来源 - http://elixir-lang.org/getting_started/4.html
考虑到这一点,您可以将新值附加到符号,如下所示:
iex> x = 1 # Outputs "1"
iex> x = 2 # Outputs "2"
我也可以这样做:
iex> x = x + 1 # Outputs "3"!
所以我的第一个问题是; Elixir变量是否可变?
看起来确实如此......在函数式编程语言中,这应该是不可能的?
所以现在我们来到"^"运算符......
iex> x = 1 # Outputs "1"
iex> x = 2 # Outputs "2"
iex> x = 1 # Outputs "1"
iex> ^x = 2 # "MatchError"
iex> ^x = 1 # Outputs "1"
我认为"^"的效果是将"x"锁定到绑定到它的最后一个值.这就是它的全部吗?为什么不确保所有'匹配'/赋值都像Erlang本身一样不可变?
我刚刚习惯了......
1> tkowal..:
Elixir中的数据仍然是不可变的,但有一些简写,可以让您输入更少或不担心找到新名称.在Erlang中,您经常可以看到如下代码:
SortedList = sort(List),
FilteredList = filter(SortedList),
List3 = do_something_with(FilteredList),
List4 = another_thing_with(List3)
在Elixir,你可以写:
list = sort(list)
list = filter(list)
list = do_something_with(list)
list = another_thing_with(list)
这是完全一样的,但看起来好一点.当然最好的解决方案是这样写:
list |> sort |> filter |> do_something |> another_thing_with
每次,你为list
变量分配新东西,你得到新的实例:
iex(1)> a = 1
1
iex(2)> b = [a, 2]
[1, 2]
iex(3)> a = 2
2
iex(4)> b
[1, 2] # first a did not change, it is immutable, currently a just points to something else
你只是说,你不再对旧的感兴趣a
,让它指向别的东西.如果你来自Erlang背景,你可能知道f
shell 的功能.
A = 1.
f(A).
A = 2.
在Elixir你只是不必写f
.它会自动为您完成.这意味着,每次在模式匹配的左侧都有变量时,您将为其分配新值.
没有^
运算符,您将无法在模式匹配的左侧使用变量,因为它将从右侧获得新值.^
表示不为此变量分配新内容 - 将其视为文字值.
这就是Elixir的原因
x = 1
[1, x, 3] = [1, 2, 3]
在Erlang中等效于:
X = 1,
[1, CompletelyNewVariableName, 3] = [1, 2, 3]
和:
x = 1
[1, ^x, 3] = [1, 2, 3]
相当于:
x = 1
[1, 1, 3] = [1, 2, 3]
在Erlang中:
X = 1,
[1, X, 3] = [1, 2, 3]
在shell中 - 是的,但你也可以在脚本中使用它,其中`f/1`是不可能的,这就是我将它与创建新变量进行比较的原因.
2> greggreg..:
elixir中的数据是不可变的,但变量虽然可以重新分配.什么可以使elixir稍微混淆是你看到的组合分配和模式匹配.
当您在左侧使用带有变量引用的等号时,首先将模式匹配结构,然后执行赋值.当你在左边只有一个唯一的变量引用时,它将匹配任何结构,因此将被分配如下:
a = 1 # 'a' now equals 1
a = [1,2,3,4] # 'a' now equals [1,2,3,4]
a = %{:what => "ever"} # 'a' now equals %{:what => "ever"}
如果左边有一个更复杂的结构,那么elixir将首先模式匹配结构,然后执行赋值.
[1, a, 3] = [1,2,3]
# 'a' now equals 2 because the structures match
[1, a] = [1,2,3]
# **(MatchError)** because the structures are incongruent.
# 'a' still equals it's previous value
如果要根据变量的内容进行值匹配,可以使用引脚'^':
a = [1,2] # 'a' now equals [1,2]
%{:key => ^a} = %{:key => [1,2]} # pattern match successful, a still equals [1,2]
%{:key => ^a} = %{:key => [3,4]} # **(MatchError)**
这个人为的例子也可以在右侧用'a'写成,没有引脚:
%{:key => [1,2]} = %{:key => a}
现在说你想把一个变量分配给一个结构的一部分但是只有当那个结构的一部分匹配存储在'a'中的东西时,在elixir中这是微不足道的:
a = %{:from => "greg"}
[message, ^a] = ["Hello", %{:from => "greg"}] # 'message' equals "Hello"
[message, ^a] = ["Hello", %{:from => "notgreg"}] # **(MatchError)**
在这些简单的例子中,引脚和模式匹配的使用并不是立即超值,但随着你学习更多的灵丹妙药并开始越来越多的模式匹配,它成为了长生不老药提供的表现力的一部分.