簡體   English   中英

“pin”運算符是什么,Elixir 變量是否可變?

[英]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 提供的表達能力的一部分。

這是我的簡約方法:

等號 (=) 不僅僅是賦值,這里發生了兩件事:

  1. 模式匹配。
  2. 如果模式匹配,那么這將導致從右到左的分配。 否則會報錯。

把“=”想象成代數,這表示等式的左邊和右邊代表相同,所以如果你有 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM