In Rails you can do something like:
@user.try(:contact_info).try(:phone_number)
Which will return the phone_number
if the @user
and contact_info
are both not nil. If one of those are nil, the expression will return nil.
I want to know what is the most idiomatic way to do this in Elixir, knowing that @user
and contact_info
are structs.
I think one way to do that is to go with pattern matching so it would be something like this:
case user do
%{contact_info: %{phone_number: phone_number}} when phone_number != nil ->
#do something when the phone number is present
_ ->
#do something when the phone number is absent
end
Edit: Testing my suggestion to use with
, I realize it won't work as it short circuits on match error, but you'll have UndefinedFunctionError
on nil. So I removed that part. I'd go with pattern matching, as @JustMichael suggested.
If you control the definition of the structs, a default value in the struct may help.
defmodule ContactInfo do
defstruct phone_number: nil
end
defmodule User do
defstruct contact_info: %ContactInfo{}
end
iex> user = %User{}
%User{contact_info: %ContactInfo{phone_number: nil}}
iex> user.contact_info.phone_number
nil
Someone could still purposely set :contact_info
to nil, but consider just letting it crash… :)
You can use get_in
from Kernel:
iex(2)> user = %{contact_info: %{name: "Bob"}}
%{contact_info: %{name: "Bob"}}
iex(3)> get_in(user, [:contact_info, :name])
"Bob"
iex(4)> user2 = %{}
%{}
iex(5)> get_in(user2, [:contact_info, :name])
nil
iex(6)> user3 = %{contact_info: %{}}
%{contact_info: %{}}
iex(7)> get_in(user3, [:contact_info, :name])
nil
Note that this will won't work with Ecto models/structs, but plain maps are fine.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With