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
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]
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
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
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
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
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}
Chú ý: import/2
, require/2
và alias/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
đ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
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
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 #elixir
ở cộ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
:)
Top comments (0)