07/09/2018, 15:52

Elixir cho dân Ruby - Phần 3

Chưa xem phần 2? Xem phần 2 Trong bài viết này tôi giới thiệu cho các bạn về khái niệm function arity, một cách gọi mĩ miều của số lượng argument của hàm. Tại sao arity lại quan trọng trong Elixir? Function Arity là cái tên hoành tá tràng của "Hàm này có bao nhiêu argument". Với ví dụ sau: ...

Chưa xem phần 2? Xem phần 2

Trong bài viết này tôi giới thiệu cho các bạn về khái niệm function arity, một cách gọi mĩ miều của số lượng argument của hàm. Tại sao arity lại quan trọng trong Elixir?

Function Arity là cái tên hoành tá tràng của "Hàm này có bao nhiêu argument". Với ví dụ sau:

defmodule LeRoiTopHits do
  def play(bai1, bai2) do
  end
end

ở đây hàm LeRoiTopHits.play sẽ có arity là 2, và mà 'tiếng lóng' dân Elixir nói chuyện với nhau là LeRoiTopHits.play /2, lưu ý dấu /. Nên nhớ cách gọi này khi nói chuyện với các chuyên gia.

Một khái niệm mới cho dân Ruby đây, vì trong Elixir, hai hàm cùng tên mà có khác số arity là hai hàm khác nhau. Hả?! Cái gì cơ? nói lại 1 tí xem, vâng để tôi lấy một ví dụ của Ruby trước nhé:

module LeRoiTopHits
  def self.play(bai1, bai2)
  end
end

# rồi sau đó tiếp tục định nghĩa thêm
module LeRoiTopHits
  def self.play(bai1)
  end
end

ở ví dụ trên thì hàm LeRoiTopHits.play(bai1) sẽ ghi đè lên hàm cũ, và trên thực tế chỉ có 1 hàm và hàm được định nghĩa lại. Nhưng với Elixir thì lại khác:

defmodule LeRoiTopHits do
  def play(bai1, bai2) do # <-- LeRoiTopHits.play /2
  end

  def play(bai1) do # <-- LeRoiTopHits.play /1
  end
end

bạn có thể gọi được 2 phiên bản của hàm play:

LeRoiTopHits.play('Tình đơn phương', 'Ngày trở về')
LeRoiTopHits.play('Tình đơn phương')

Vâng, tuy là cùng tên hàm nhưng logic bên trong có thể hoàn toàn khác nhau tuỳ vào số argument người dùng cung cấp. Thường thì không có nghĩa lắm nếu 2 logic khác nhau hoàn toàn, đa số các trường hợp là bổ trợ cho nhau.

Và cũng thường thấy pattern là hàm nào có số arity thấp thường delegate (uỷ thác) cho hàm cùng tên với số arity cao hơn, kèm theo một giá trị argument mặc định. Chúng ta hãy cùng xem một ví dụ:

defmodule LeRoiTopHits do
  def play(bai1) do
    play(bai1, "Tình đơn phương")
  end

  def play(bai1, bai2) do
  end
end

ở trên chúng ta thấy là LeRoiTopHits.play /1 sẽ cung cấp argument số 2 với giá trị mặc định là "Tình đơn phương" cho LeRoiTopHits.play /2.

Cái pattern này trở nên rất thông dụng đến nỗi Elixir cung cấp một cách viết ngắn với từ khoá , ví dụ trên có thể được viết thành:

defmodule LeRoiTopHits do
  def play(bai1, bai2  "Tình đơn phương") do
  end
end

Ngoài ra chúng ta có thể kết hợp giá trị mặc định cho nhiều argument khác:

defmodule LeRoiTopHits do
  def play(bai1, bai2  "Tình đơn phương", bai3  "Tra tấn") do
  end
end

Code ở trên sẽ tạo ra 3 hàm: LeRoiTopHits.play /1, LeRoiTopHits.play /2 và `LeRoiTopHits.play /3.

Bởi vì arity giúp phân biệt rõ ràng hàm cùng tên nên chúng ta có thể xoá bỏ hoàn toàn các câu lệnh if/else của Ruby.

Function Arity là số argument một hàm nhận vào. Hàm có cùng tên nhưng khác arity được xem như khác nhau, và sử dụng từ khoá để cài giá trị mặc định của một argument. Với arity, chúng ta có thể xoá bỏ hoàn toàn các câu lệnh if/else.

Trong bài tiếp theo, chúng ta sẽ bàn về function encapsulation, cách import module và cách tạo alias.

0