Reputation: 772
How can I implement multiple if conditions in my code like below
person = %Person{}
if x.name == "Test" do
person = %{person | name: "Test"}
end
if x.age == 50 do
person = %{person | age: 50}
end
here "x" is another object where I am trying to validate data and then updating person struct accordingly. I already wrote code as above but got a below warning
the variable "person" is unsafe as it has been set inside one of: case, cond, receive, if, and, or, &&, ||. Please explicitly return the variable value instead. For example:
case integer do 1 -> atom = :one 2 -> atom = :two end
should be written as
atom = case integer do 1 -> :one 2 -> :two end
Upvotes: 1
Views: 4636
Reputation: 121000
Everything in Elixir is immutable. I would suggest you to read this great writing by José Valim on rebinding variables in Elixir.
The functionality you are after looks mostly as a reducing the struct
on a list of fields, that’s why I probably would go with Enum.reduce/3
:
defmodule Person, do: defstruct ~w|foo name age|a
x = [name: true, age: false] # flags
~w|name age|a
|> Enum.zip(['Test', 50])
|> Enum.reduce(%Person{foo: :bar}, fn {field, value}, acc ->
if x[field], do: %{acc | field => value}, else: acc
end)
#⇒ %Person{age: nil, foo: :bar, name: 'Test'}
Upvotes: 2
Reputation: 8274
When you are matching multiple clauses to validate a field, I would combine functions that validate the pieces, as follows:
defmodule PersonChecker do
def validate(x, person) do
person
|> validate_name(x)
|> validate_age(x)
end
defp validate_name(person, %{name: name}) when name == "Test" do
%{person | name: "Test"}
end
defp validate_name(person, _x), do: person
defp validate_age(person, %{age: age}) when age == 50 do
%{person | age: 50}
end
defp validate_age(_x, person), do: person
end
If you wanted to use case
instead of multiple validate_name
functions it would look like this:
defp validate_name(person, x) do
case x.name do
"Test" -> %{person | name: "Test"}
_ -> person
end
end
As an aside, depending on your use case, it might be easier to muck with x
to strip out the fields you don't want, and then convert x
into a struct using the struct(Person, x)
function.
Upvotes: 3
Reputation: 2901
You can't rebind the variable inside the block. As the error message suggest, set it explicit:
person = %Person{}
person = if x.name == "Test", do: %{person | name: "Test"}, else: person
person = if x.age == 50, do: %{person | age: 50}, else: person
Even if variables are immutable, Elixir allows rebinding, but it would be easier to understand if it would not be allowed (like in Erlang). In this case, you would have to write something like:
person = %Person{}
person_with_name = if x.name == "Test", do: %{person | name: "Test"}, else: person
person_with_name_and_age = if x.age == 50, do: %{person_with_name | age: 50}, else: person_with_name
Upvotes: 2