Reputation: 107
I'm looping on list of values and in the list I have a case to choose what should be returned. The code loop code looks like:
value = code &&& key
IO.puts "+++++"
IO.puts "key:#{key},code:#{code},code &&& key:#{value},value == key:#{value == key}"
case value do
key -> IO.puts "value is true"
_ -> IO.puts "value is false"
end
The log output of those calls is:
+++++
key:1,code:1,code &&& key:1,value == key:true
value is true
+++++
key:2,code:1,code &&& key:0,value == key:false
value is true
+++++
key:4,code:1,code &&& key:0,value == key:false
value is true
+++++
key:8,code:1,code &&& key:0,value == key:false
value is true
+++++
key:16,code:1,code &&& key:0,value == key:false
value is true
I'm getting always the "value is true" and we can clearly see the case value is false. What happens here?
Thanks for any help.
Upvotes: 2
Views: 80
Reputation: 23091
You are printing value is true
, but that's not actually the case. You should put the expected value to the left of the ->
.
one = 1
case one do
true -> IO.puts("value is true")
false -> IO.puts("value is false")
end
This produces: ** (CaseClauseError) no case clause matching: 1
The problem with using variables on the left is that the variables are rebound to that scope. If there is already a variable of that name, it will get re-bound during the case statement:
one = 1
two = 2
case one do
two -> IO.puts("value matches itself (#{two})")
_ -> throw("neven happens")
end
This prints value matches itself (1)
, because one
is assigned to two
and always matches itself.
In the case where the expected value is in a variable, you need to use the pin operator as Justin Wood pointed out:
one = 1
two = 2
case one do
^two -> IO.puts("value matches the variable in two")
_ -> IO.puts("#{one} doesn't match #{two}")
This prints 1 doesn't match 2
.
By the way, the reason for this behaviour is so that you can do pattern matching with the left hand side and capture the variable for use on the right:
map = %{a: "a", b: "b"}
case map do
%{a: a} -> IO.puts("map's a key contains a value of #{a}")
_ -> IO.puts("map doesn't contain key a")
end
Upvotes: 0
Reputation: 10061
This is exactly how a case expression should be working. You put the value of value
into the key
variable. If you want to match value
against the current value of the key
variable instead of shadowing it, you will need to use the pin operator.
case value do
^key -> ...
_ -> ...
end
Upvotes: 5