[英]What is the "pin" operator for, and are Elixir variables mutable?
目前正在嘗試了解 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 本身一樣不可變?
我只是習慣了...
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 背景,你可能知道 shell 中的f
函數。
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]
Elixir 中的數據是不可變的,但變量是可以重新分配的。 使 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)**
在這些簡單的例子中,pin 和模式匹配的使用並不是立即就非常有價值,但是隨着你學習更多的 elixir 並越來越多地開始模式匹配,它成為 elixir 提供的表達能力的一部分。
這是我的簡約方法:
等號 (=) 不僅僅是賦值,這里發生了兩件事:
把“=”想象成代數,這表示等式的左邊和右邊代表相同,所以如果你有 x = 1,x 的唯一值是 1。
iex(1)> x = 1 # 'x' matches 1
1
iex(2)> x # inspecting the value of 'x' we get 1, like in other languages
1
iex(3)> x = 2 # 'x' matches 2
2
iex(4)> x # now 'x' is 2
2
那么我們如何使用“x”進行比較而不是為其分配新值?
我們需要使用 pin 運算符 ^:
iex(5)> ^x = 3
** (MatchError) no match of right hand side value: 3
我們可以看到 'x' 值仍然是 2。
iex(5)> x
2
問題:了解 Elixir 的 pin 運算符
^
的最佳方法是使用相關示例。
允許用戶在更改密碼之前更改密碼,他們必須提供新密碼和以前的密碼。
解決方案:在像 JavaScript 這樣的語言中,我們可以像這樣編寫一個簡單的解決方案
let current_password = 'secret-1'; const params = { new_password: 'secret-2', current_password: 'secret-2' } if (current_password !== params.current_password) { throw "Match Error" }
以上將拋出Match Error
因為用戶提供的密碼與他們當前的密碼不匹配
使用 Elixir 的pin 運算符,我們可以將上面的內容寫為
iex(1)> x = 1
1
iex(2)> ^x = 1 # Matches previous value 1
1
iex(3)> ^x = 2 # Does not match previous value
** (MatchError) no match of right hand side value: 2
以上也會MatchError
異常
使用 pin 運算符^
對現有變量的值進行模式匹配。 在上面的 Elixir 示例中,變量new_password
綁定到元組中的第一項(用{}
表示的 Elixirs 數據結構),而不是重新綁定current_password
變量,我們對其現有值進行模式匹配。
現在這個來自 Elixir 文檔的例子應該是有意義的。
iex(1)> x = 1 1 iex(2)> ^x = 1 # Matches previous value 1 1 iex(3)> ^x = 2 # Does not match previous value ** (MatchError) no match of right hand side value: 2
模式匹配將左側的值與右側的值匹配。 如果匹配並且左側包含變量,則將右側的相應值分配給變量。
Caret(^) 運算符將變量固定在其值上,並在使用模式匹配時防止對該變量進行任何賦值。
參考: https : //medium.com/@Julien_Corb/understand-the-pin-operator-in-elixir-a6f534d865a6
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.