Run this notebook

Use Livebook to open this notebook and explore new ideas.

It is easy to get started, on your machine or the cloud.

Click below to open and run it in your Livebook at .

(or change your Livebook location)

# Pattern Matching Pattern matching is extremely powerful in Elixir and you'll use it all the time. Let's see some examples: ## Match against Basic Types ```elixir # You can match against many data structures, like a map. # This is a partial match, meaning the 'height' value gets ignored. %{age: age, name: name} = %{age: 32, name: "Peter", height: 190.47} IO.inspect([age, name], label: 1) # Or a Tuple. You can't match partially though. {a, _, c} = {1, 2, 3} IO.inspect([a, c], label: 2) # Or a Keyword list, but you can't match partially either. [a: a, b: _b, c: c] = [a: 1, b: 2, c: 3] IO.inspect([a, c], label: 3) # Or a list, but again, not partially. [a, b, _] = [1, 2, 3] IO.inspect([a, b], label: 4) # But you can match against the head (first element) and tail (the rest) of a list. [head | tail] = [1, 2, 3] IO.inspect(head, label: "5 - head") IO.inspect(tail, label: "5 - tail") ``` <!-- livebook:{"output":true} --> ``` 1: [32, "Peter"] 2: [1, 3] 3: [1, 3] 4: [1, 2] 5 - head: 1 5 - tail: [2, 3] ``` ### Caveat: Matching against empty Maps Watch out if you want to match against an empty map, because Elixir will match any map with an empty map, even if the map isn't empty. ```elixir defmodule RunElixir.Match do def empty?(%{}), do: true def empty?(_), do: false end RunElixir.Match.empty?(%{}) # => true RunElixir.Match.empty?(%{a: 1, b: 2}) # => true # You can either use the 'map_size/1' guard defmodule RunElixir.MatchSize do def empty?(map) when map_size(map) == 0, do: true def empty?(_), do: false end RunElixir.MatchSize.empty?(%{}) # => true RunElixir.MatchSize.empty?(%{a: 1, b: 2}) # => false # Or a comparison to match against an empty map defmodule RunElixir.MatchEqual do def empty?(map) when map == %{}, do: true def empty?(_), do: false end RunElixir.MatchEqual.empty?(%{}) # => true RunElixir.MatchEqual.empty?(%{a: 1, b: 2}) # => false ``` ## Match in Function Clauses ```elixir # You can match (partially) in (anonymous) function clauses. # # This here defines an anonymous function with two clauses. # It's the same as defining two function clauses in a module # like we've done with 'def empty?()' above, just that # the function isn't wrapped in a module. fun = fn %{status: status} -> status %{age: age} -> age end fun.(%{status: :active, height: 190.47}) # => :active fun.(%{age: 32, height: 190.47}) # => 32 # Or in Module functions defmodule RunElixir.Profile do def details(%{status: status}), do: status def details(%{age: age}), do: age end RunElixir.Profile.details(%{status: :inactive, height: 190.47}) # => :inactive RunElixir.Profile.details(%{age: 30, height: 190.47}) # => 30 ``` ## Match against Strings ```elixir # You can match against the end of a string "My name is " <> name = "My name is Batman" IO.inspect(name, label: 1) # Or you can match against specific bytes # # This is extremely useful for deconstructing a string into fixed-size byte chunks. # For example, to implement a communication protocol for which you know that # the first 3 bytes are one argument, and the next 8 bytes are the second, and so on. <<article::binary-size(3), _space::binary-size(1), name::binary-size(6), rest::binary>> = "The Batman is my name" IO.inspect(article, label: "2 - article") IO.inspect(name, label: "2 - name") IO.inspect(rest, label: "2 - rest") ``` <!-- livebook:{"output":true} --> ``` 1: "Batman" 2 - article: "The" 2 - name: "Batman" 2 - rest: " is my name" ``` ## The Pin Operator The Pin `^` operator allows you to match against the value of an existing variable: ```elixir name = "Peter" fun = fn %{name: ^name} -> "That's me!" %{name: _name} -> "That's not me." end fun.(%{name: "Peter"}) # => "That's me!" fun.(%{name: "Bob"}) # => "That's not me." ``` ## Assignment is Matching Fun fact: In Elixir there is no such thing as a "variable assignment". It's match! When you assign a value to a variable, you actually "match" the value against the variable and because that match is always true, the variable will continue to hold the value. This becomes clearer when we pin the variable: ```elixir a = 1 a = 2 ^a = 3 ``` <!-- livebook:{"output":true} --> ``` ** (MatchError) no match of right hand side value: 3 (stdlib 6.0) erl_eval.erl:652: :erl_eval.expr/6 ``` Interesting! When we pin the variable `a` and try to assign a new value to it, it raises a `MatchError`! This happens because `a` holds the value `2` when we try to match it agains the value `3`, which creates a mismatch (Got it? Mis-match! 😬). This shows that the `=` operator is actually a match, not an assignment. Today you learned!
See source

Have you already installed Livebook?

If you already installed Livebook, you can configure the default Livebook location where you want to open notebooks.
Livebook up Checking status We can't reach this Livebook (but we saved your preference anyway)
Run notebook

Not yet? Install Livebook in just a minute

Livebook is open source, free, and ready to run anywhere.

Run on your machine

with Livebook Desktop

Run in the cloud

on select platforms

To run on Linux, Docker, embedded devices, or Elixir’s Mix, check our README.

PLATINUM SPONSORS
SPONSORS
Code navigation with go to definition of modules and functions Read More ×