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.)