Do you want to pick up from where you left of?
Take me there

Struktur Kendali

Dalam pelajaran ini kita akan melihat struktur kendali yang tersedia untuk kita di Elixir.

Table of Contents

if dan unless

Besar kemungkinan anda sudah bertemu if/2 sebelumnya, dan jika sudah terbiasa dengan Ruby anda juga sudah familiar dengan unless/2. Dalam Elixir keduanya berfungsi cukup mirip tetapi keduanya didefinisikan sebagai macro, bukannya fasilitas bahasa; Anda dapat melihat implementasinya di modul Kernel.

Harus dicatat bahwa di Elixir, nilai yang dianggap false (falsey value) hanyalah nil dan boolean false.

iex> if String.valid?("Hello") do
...>   "Valid string!"
...> else
...>   "Invalid string."
...> end
"Valid string!"

iex> if "a string value" do
...>   "Truthy"
...> end
"Truthy"

Menggunakan unless/2 adalah seperti if/2 hanya saja bekerja pada yang false:

iex> unless is_integer("hello") do
...>   "Not an Int"
...> end
"Not an Int"

case

Jika diperlukan untuk mencocokkan pada banyak pola kita dapat menggunakan case/2:

iex> case {:ok, "Hello World"} do
...>   {:ok, result} -> result
...>   {:error} -> "Uh oh!"
...>   _ -> "Catch all"
...> end
"Hello World"

Variabel _ adalah bagian yang penting dalam pernyataan case/2. Tanpa itu kegagalan menemukan kecocokan akan menghasilkan error:

iex> case :even do
...>   :odd -> "Odd"
...> end
** (CaseClauseError) no case clause matching: :even

iex> case :even do
...>   :odd -> "Odd"
...>   _ -> "Not Odd"
...> end
"Not Odd"

Anggaplah _ sebagai else yang akan cocok dengan “semua yang lain. Karena case/2 bergantung pada pencocokan pola, semua aturan dan batasan yang sama berlaku. Jika anda berniat untuk mencocokkan terhadap variabel yang sudah ada isinya anda harus menggunakan operator pin ^/1:

iex> pie = 3.14
 3.14
iex> case "cherry pie" do
...>   ^pie -> "Not so tasty"
...>   pie -> "I bet #{pie} is tasty"
...> end
"I bet cherry pie is tasty"

Satu lagi fitur case/2 yang menarik adalah dukungannya terhadap klausa penjaga (guard clause):

Contoh ini diambil langsung dari panduan resmi Awal Mulai Elixir.

iex> case {1, 2, 3} do
...>   {1, x, 3} when x > 0 ->
...>     "Will match"
...>   _ ->
...>     "Won't match"
...> end
"Will match"

Ceklah dokumentasi resmi untuk Expression yang diijinkan dalam klausa penjaga.

cond

Ketika kita perlu mencocokkan kondisi, dan bukannya value, kita dapat menggunakan cond; ini seperti else if atau elsif di bahasa-bahasa lain:

Contoh ini diambil langsung dari panduan resmi Awal Mulai Elixir.

iex> cond do
...>   2 + 2 == 5 ->
...>     "This will not be true"
...>   2 * 2 == 3 ->
...>     "Nor this"
...>   1 + 1 == 2 ->
...>     "But this will"
...> end
"But this will"

Seperti case/2, cond/1 akan menghasilkan error kalau tidak ada kecocokan. Untuk menangani ini, kita dapat mendefinisikan sebuah kondisi untuk true:

iex> cond do
...>   7 + 1 == 0 -> "Incorrect"
...>   true -> "Catch all"
...> end
"Catch all"

with

Bentuk spesial with/1 berguna ketika anda ingin menggunakan sebuah pernyataan case/2 bertingkat atau situasi yang tidak dapat di-pipe dengan mudah. Ekspresi with/1 terdiri dari keyword, generator, dan akhirnya sebuah expression.

Kita akan diskusikan generator lebih jauh di Daftar Pelajaran Pemahaman, tapi sementara ini kita hanya perlu mengetahui bahwa mereka menggunakan pencocokan pola untuk membandingkan sisi kanan dari <- terhadap sisi kiri.

Kita akan mulai dengan contoh sederhana dari with/1 dan kemudian melihat lebih jauh:

iex> user = %{first: "Sean", last: "Callan"}
%{first: "Sean", last: "Callan"}
iex> with {:ok, first} <- Map.fetch(user, :first),
...>      {:ok, last} <- Map.fetch(user, :last),
...>      do: last <> ", " <> first
"Callan, Sean"

Dalam kondisi dimana sebuah expression gagal mendapati kecocokan, value yang tidak cocok akan dikembalikan:

iex> user = %{first: "doomspork"}
%{first: "doomspork"}
iex> with {:ok, first} <- Map.fetch(user, :first),
...>      {:ok, last} <- Map.fetch(user, :last),
...>      do: last <> ", " <> first
:error

Sekarang mari lihat contoh yang lebih besar tanpa with/1 dan kemudian melihat bagaimana kita bisa merefaktornya:

case Repo.insert(changeset) do
  {:ok, user} ->
    case Guardian.encode_and_sign(user, :token, claims) do
      {:ok, token, full_claims} ->
        important_stuff(token, full_claims)

      error ->
        error
    end

  error ->
    error
end

Ketika kita menggunakan with/1 kita dapati code yang mudah dipahami dan menggunakan jumlah line yang lebih sedikit:

with {:ok, user} <- Repo.insert(changeset),
     {:ok, token, full_claims} <- Guardian.encode_and_sign(user, :token, claims) do
  important_stuff(token, full_claims)
end

Seperti pada Elixir 1.3, with/1 mendukung pernyataan else:

import Integer

m = %{a: 1, c: 3}

a =
  with {:ok, number} <- Map.fetch(m, :a),
       true <- is_even(number) do
    IO.puts("#{number} divided by 2 is #{div(number, 2)}")
    :even
  else
    :error ->
      IO.puts("We don't have this item in map")
      :error

    _ ->
      IO.puts("It is odd")
      :odd
  end

Ini membantu menangani kesalahan dengan menyediakan pencocokan pola case seperti di dalamnya. Nilai yang dilewatkan adalah ekspresi non-matching pertama.

Caught a mistake or want to contribute to the lesson? Edit this lesson on GitHub!