Pattern Matching Structured Data

Matching goes further—Elixir will look at the structure of the two sides when making a match:

 [ a, b, c ] = [1, 2, 3] ​#​ a = 1, b = 2, c = 3
 [ head | tail ] = [1, 2, 3] ​#​ head = 1, tail = [ 2, 3 ]

Once bound, a variable keeps the same value for the duration of the pattern match. So the following match will only succeed if the variable list is a three-element list where the first and last elements have the same value:

 [ a, b, a ] = list

You can mix constants and variables on the left-hand side. To illustrate this, I’m going to introduce a new Elixir data type, the tuple. A tuple is a fixed-length collection of values. We write tuple constants between braces:

 { 1, 2, ​"cat"​ }
 { :ok, result }

(The :ok in the second line of code is an Elixir symbol. You can think of it as a constant string, or as a symbol in Ruby. You can also think of it as a constant whose value is its name, but that can lead to catatonic states.)

Many library functions return two-element tuples. The first element will be the status of the result—if it is :ok, the call succeeded; if it is :error, it failed. The second value will be the actual result of the call, with more information on the error.

You can use pattern matching to determine if a call succeeded:

 { :ok, stream } = File.open(​"somefile.txt"​)

If the File.open succeeds, then stream will be set to the result. If it doesn’t, the pattern won’t match, and Elixir will raise a runtime error. (Although in this case, you’re better off opening the file with File.open!(), which will raise a more meaningful error on failure.)