DEV Community

Toan Ha for OnPoint Vietnam

Posted on

Phân biệt các từ khóa use, alias, require và import

Khi mới tiếp cận với Elixir các bạn có thể sẽ phân vân điểm khác nhau giữa các từ khoá trên. Bài viết này so sánh các từ khoá đó thông qua cách sử dụng

1. import

Hiểu đơn giản nó sẽ bê toàn bộ functions và macros của module B vô module A để sử dụng. Mình có thể gọi tắt 1 function trong B mà không cần bắt đầu bằng tên module.

defmodule A do
  def say_world() do
    IO.puts("world")
  end

  defmacro if_unless(expr, opts) do
    quote do
      if !unquote(expr), unquote(opts)
    end
  end
end

defmodule B do
  import A

  def say_hello do
    IO.puts("Hello ")
    if_unless false do
      say_world()
    end
  end
end
Enter fullscreen mode Exit fullscreen mode

Có thể sử dụng thêm 2 từ khóa only nếu chỉ muốn lấy 1 số hàm, marco hoặc từ khóa except nếu muốn loại từ hàm hay macro nào đó

import List, only: [flatten: 1]
import String, except: [split: 2]
Enter fullscreen mode Exit fullscreen mode

Import có thể sử dụng bên trong function và có scope chỉ ở trong function đó.

defmodule Math do
    def some_function do
        # 1) Disable "if/2" from Kernel
        import Kernel, except: [if: 2]

        # 2) Require the new "if/2" macro from MyMacros
        import MyMacros

        # 3) Use the new macro
        if do_something, it_works
    end
end
Enter fullscreen mode Exit fullscreen mode

Lưu ý: Các hàm bắt đầu bằng _ sẽ không được import. Ví dụ: (__build__, ...)

2. require

Khi muốn sử dụng marco của 1 module nào đó, bắt buộc phải require module đó trước khi gọi marco

defmodule A do
  def say_world() do
    IO.puts("world")
  end

  defmacro if_unless(expr, opts) do
    quote do
      if !unquote(expr), unquote(opts)
    end
  end
end

defmodule B do
  require A

  def say_hello do
    IO.puts("Hello ")

    A.if_unless false do
      A.say_world()
    end
  end
end
Enter fullscreen mode Exit fullscreen mode

3. alias

Dùng để setup 1 alias name cho 1 module. Mặc định thì alias sẽ lấy phần cuối cùng trong tên module làm tên alias.

defmodule A do
    alias Foo.Bar.Baz

    def funcA do
        Baz.some_func()
    end
end
Enter fullscreen mode Exit fullscreen mode

Có thể sử dụng key as để định nghĩa 1 tên khác.

defmodule A do
    alias Foo.Bar.Baz, as: FBar

    def funcA do
        FBar.some_func()
    end
end
Enter fullscreen mode Exit fullscreen mode

Mình có thể định nghĩa nhiều alias có module tương tự nhau trong cùng 1 hàng

alias Foo.Bar
alias Foo.Baz
alias Foo.Biz

> alias Foo.{Bar, Baz, Biz}
Enter fullscreen mode Exit fullscreen mode

Chú ý: import/2, require/2alias/2 có thế định nghĩa trong từng function khác nhau không nhất thiết phải để ngay sau defmodule và nó không ảnh hưởng scope lẫn nhau.

4. use

Thường xài kiểu như abstract, Khi module B use module A, nó sẽ invoke marco __using__ trong module A

defmodule A do
  defmacro __using__(opts) do
    quote do
      IO.puts("Hello ")
    end
  end
end

defmodule B do
  use A, key1: "abc"

  def say_hello do
    IO.puts("World")
  end
end
Enter fullscreen mode Exit fullscreen mode

đoạn code trên tương đương với

defmodule B do
  B.__using__([key1: "abc"])

  def say_hello do
    IO.puts("World")
  end
end
Enter fullscreen mode Exit fullscreen mode

use thường được dùng khi muốn định nghĩa 1 behavior cho 1 module. Ví dụ trong Phoenix Framework. Controller được định nghĩa

defmodule ApiWeb do
...
    def controller do
        quote do
            use Phoenix.Controller, namespace: ApiWeb
            import Plug.Conn
            import ApiWeb.Router.Helpers
            import ApiWeb.Gettext
            require Logger
        end
    end
...
end

defmodule ApiWeb.PageController do
    use ApiWeb, :controller
    ...
end
Enter fullscreen mode Exit fullscreen mode

Lưu ý: Không nên định nghĩa hàm ở trong __using__/1

Kết

Các bạn có thể tham gia vào channel #elixircộng đồng Ruby Việt Nam để thảo luận thêm về các vấn đề khi lập trình với elixir :)

Discussion (0)