Elixir 101: Extras
Kernel & Kernel.SpecialForms
Structs… continued
defmodule User do
defstruct [:name]
end
User |> Map.from_struct()
{:ok, val} = %{a: 7} |> Map.fetch(:a)
val
{:ok, name} = %User{name: "Shaniqua"} |> Map.fetch(:name)
name
{:ok, name} = %User{} |> Map.fetch(:name)
name
:error = %User{} |> Map.fetch(:field_without_a_key_in_a_user_struct)
The double equals (==
) equality operator tests for equality of left-hand and right-hand side values
The single equals (=
) match operator tries to match whatever is on the left-hand side with whatever is on the right-hand side
%User{}
generates a User struct with the default values for the User struct keys
The following creates identical structs and tests whether they’re equal using the ==
operator
%User{} == %User{name: nil}
%User{name: "john"} |> Map.from_struct()
%User{name: "john"} |> Map.from_struct() |> (fn map -> struct(User, map) end).()
%User{name: "john"} |> Map.from_struct() |> (&struct(User, &1)).()
Pattern Matching != Assignment (redux)
y = 3
Erlang is immutable and will NOT allow you to rebind a variable to a new value. Erlang “variables” really aren’t variables, they’re effectively constants.
Elixir data structures are immutable, but an Elixir variable (which can point at an Elixir data structure) can be re-bound to point at a different data structure.
You can, for example, re-bind the left-hand side variable to the evaluated value of the right-hand side, even if the left-hand side variable is currently equal to a different value.
y = y + 1
When you do this, however, the underlying data structure does NOT change. So if anyone else holds another reference to that data structure, their reference will still point at the original data structure.
In this example, the “data structure” is just an integer, but you can see that the value of b
does not change when the value of a
changes, even though they initially pointed at the very same data structure (i.e., the value 7
).
a = b = 7
"a = #{a}, b = #{b}"
a = 8
"a = #{a}, b = #{b}"
To prevent re-binding a variable and insist on matching against a variable’s current value, we use “the pin operator” (^).
The pin operator prevents variable re-binding.
If a match succeeds, the result of evaluating the line is the value of the right-hand side.
^y = 4
If attempting to pattern match fails, a MatchError
is generated:
# Since `y` is currently bound to the value 4, this pattern-match will fail with a `MatchError`:
# "** (MatchError) no match of right hand side value: 5"
^y = 5
z = 5
^z = 5
x = %{1 => "a", 2 => "b", 3 => "c"}
Because x
is equal to that map, you can now also successfully pattern-match in the opposite direction:
%{1 => "a", 2 => "b", 3 => "c"} = x
Extracting values from Maps
x[1]
Map.get(x, 2)
The following will all successfully pattern-match because everything on the left-hand side of the match operator (i.e., “=”) is present and identical on the right-hand side:
%{1 => "a", 2 => "b", 3 => "c"} = %{1 => "a", 2 => "b", 3 => "c"}
%{1 => "a", 2 => "b"} = %{1 => "a", 2 => "b", 3 => "c"}
%{3 => "c"} = %{1 => "a", 2 => "b", 3 => "c"}
%{} = %{1 => "a", 2 => "b", 3 => "c"}
The following will all FAIL to pattern-match (raising MatchError
s) because something on the left-hand side is either not present on the right-hand side or is different on the right-hand side:
# These will all fail with an "(MatchError) no match of right hand side value" error message
# %{1 => "a", 2 => "b", 3 => "c"} = %{1 => "a", 2 => "b"}
# %{1 => "a", 2 => "c"} = %{1 => "a", 2 => "b"}
# %{1 => "a", 2 => "c"} = %{1 => "a"}
# %{1 => "b"} = %{1 => "a"}
%{1 => "b"} = %{}
We can extract desired values into named variables via pattern-matching:
%{3 => value_of_3} = %{1 => "a", 2 => "b", 3 => "c"}
value_of_3
Documentation
Elixir documentation is amazing, but you’ll want to become comfortable surfing it for what you need because functions & macros can live in nooks and crannies.
I’ve just started using the Dash code browser (NOT FREE: $30).
I prefer free & open-source tools (and have used tools like DevDocs/DevDogs):
But Dash is cool because it lets me search Elixir docs, Erlang docs, and even Hex packages, like Phoenix.
I have no relationship with Kapeli, other than just having bought it.
Elixir & Erlang docs are searchable!!!
- Typing “erl:” scopes your queries to just Erlang docs
- Typing “elixir:” scopes your queries to just Elixir docs
And ALL Hex docs are downloadable & (then) searchable!!!
- Typing “hex:” scopes your queries to Hex packages you have already downloaded
Many thanks to those developers who have improved Elixir & Erlang’s documentation and helped to standardize them!!!