Elixir:使用与导入
Elixir: use vs import
use
和 import
有什么区别?
use is a simple mechanism for using a given module into the current context
https://hexdocs.pm/elixir/Kernel.SpecialForms.html#import/2
Imports function and macros from other modules
看起来有一个区别是 import
让您选择特定的 functions/macros 而 use
将所有内容都包含在内。
还有其他区别吗?你什么时候会用一个而不是另一个?
use
用于将代码注入当前模块,而 import
用于导入函数以供使用。您可以构建一个自动导入函数的 use
实现,例如,当您将 use Timex
添加到模块 take a look at timex.ex if you want to know what I mean 时,我对 Timex 所做的,这是一个如何构建一个非常简单的示例可以 use
'd
的模块
import Module
将 Module
的所有函数和宏都以未命名空间的形式引入您的模块。
require Module
允许您使用 Module
的宏,但不导入它们。 (Module
的函数始终可用命名空间。)
use Module
首先是 requires
模块,然后在 Module
.
上调用 __using__
宏
考虑以下因素:
defmodule ModA do
defmacro __using__(_opts) do
IO.puts "You are USING ModA"
end
def moda() do
IO.puts "Inside ModA"
end
end
defmodule ModB do
use ModA
def modb() do
IO.puts "Inside ModB"
moda() # <- ModA was not imported, this function doesn't exist
end
end
这将无法编译,因为 ModA.moda()
尚未导入到 ModB
。
以下将通过编译:
defmodule ModA do
defmacro __using__(_opts) do
IO.puts "You are USING ModA"
quote do # <--
import ModA # <--
end # <--
end
def moda() do
IO.puts "Inside ModA"
end
end
defmodule ModB do
use ModA
def modb() do
IO.puts "Inside ModB"
moda() # <-- all good now
end
end
当您 use
d ModA
时,它生成了一个 import
语句,该语句被插入 ModB
.
use Module
需要 Module
并在其上调用 __using__
。
import Module
将 Module
功能引入 当前上下文 ,而不仅仅是需要它。
请参阅 elixir 官方入门指南中的 «alias, require, and import» 页:
# Ensure the module is compiled and available (usually for macros)
require Foo
# Import functions from Foo so they can be called without the `Foo.` prefix
import Foo
# Invokes the custom code defined in Foo as an extension point
use Foo
需要
Elixir 提供宏作为元编程(编写生成代码的代码)的机制。
宏是在编译时执行和扩展的代码块。这意味着,为了使用宏,我们需要保证其模块和实现在编译期间可用。这是通过 require
指令完成的。
一般情况下,一个模块在使用前不需要是必需的,除非我们想使用该模块中可用的宏。
导入
每当我们想在不使用完全限定名称的情况下轻松访问其他模块的函数或宏时,我们都会使用 import
。例如,如果我们想多次使用 List
模块中的 duplicate/2
函数,我们可以导入它:
iex> import List, only: [duplicate: 2]
List
iex> duplicate :ok, 3
[:ok, :ok, :ok]
在这种情况下,我们仅从 List
.
导入函数 duplicate
(具有 arity 2)
请注意 import
会自动 require
安装一个模块。
使用
虽然不是指令,但 use
是一个与 require
紧密相关的宏,允许您在当前上下文中使用模块。 use
宏经常被开发人员用来将外部功能引入当前词法范围,通常是模块。
在幕后,use
需要给定的模块,然后对其调用 __using__/1
回调,允许模块将一些代码注入当前上下文。一般来说,以下模块:
defmodule Example do
use Feature, option: :value
end
编译成
defmodule Example do
require Feature
Feature.__using__(option: :value)
end
我有 Python/Java/Golang 语言背景,import
与 use
也让我感到困惑。这将通过一些声明性语言示例解释代码重用机制。
导入
简而言之,在 Elixir 中,您不需要导入模块。所有 public 函数都可以通过完全限定的 MODULE.FUNCTION 语法访问:
iex()> Integer.mod(5, 2)
1
iex()> String.trim(" Hello Elixir ")
"Hello Elixir"
在 Python/Java/Golang 中,您需要 import MODULE
才能使用该模块中的功能,例如 Python
In []: import math
In []: math.sqrt(100)
Out[]: 10.0
那么 Elixir 中 import
的功能可能会让您大吃一惊:
We use import whenever we want to easily access functions or macros from other modules without using the fully-qualified name
https://elixir-lang.org/getting-started/alias-require-and-import.html#import
因此,如果您想键入 sqrt
而不是 Integer.sqrt
,trim
而不是 String.trim
,import
会有所帮助
iex()> import Integer
Integer
iex()> sqrt(100)
10.0
iex()> import String
String
iex()> trim(" Hello Elixir ")
"Hello Elixir"
这可能会导致阅读代码时出现问题,并且当存在名称冲突时,它在 Erlang(影响 Elixir 的语言)中是 not recommended。但是 Elixir 中没有这样的约定,您可以自行承担风险。
在Python中,同样的效果可以通过:
from math import *
它只推荐使用 in some special scenarios / 交互模式 - 用于 shorter/faster 打字。
使用和要求
use
/require
的不同之处在于它们与 "macro" 相关 - Python/Java/Golang... 系列中不存在的概念。
你不需要import
一个模块来使用它的功能,但是你需要require
一个模块来使用它的宏:
iex()> Integer.mod(5, 3) # mod is a function
2
iex()> Integer.is_even(42)
** (CompileError) iex:3: you must require Integer before invoking the macro Integer.is_even/1
(elixir) src/elixir_dispatch.erl:97: :elixir_dispatch.dispatch_require/6
iex()> require Integer
Integer
iex()> Integer.is_even(42) # is_even is a macro
true
虽然is_even
可以写成普通函数,但它是一个宏,因为:
In Elixir, Integer.is_odd/1 is defined as a macro so that it can be used as a guard.
https://elixir-lang.org/getting-started/alias-require-and-import.html#require
use
,摘自 Elixir 文档:
use requires the given module and then calls the __using__/1
callback on it allowing the module to inject some code into the current context.
defmodule Example do
use Feature, option: :value
end
编译成
defmodule Example do
require Feature
Feature.__using__(option: :value)
end
https://elixir-lang.org/getting-started/alias-require-and-import.html#use
所以写use X
和写
是一样的
require X
X.__using__()
use/2
is a macro,宏会为您将代码转换成其他代码。
你会想要 use MODULE
当你:
- 想要访问其宏 (
require
)
- 并执行
MODULE.__using__()
在 Elixir 1.5 上测试
导入
使给定模块中的所有函数和宏都可以在调用它的词法范围内访问。请记住,在大多数情况下,您只需要导入一个或多个 functions/macros。
示例:
defmodule TextPrinter do
import IO, only: [puts: 1]
def execute(text) do
puts(text)
end
end
iex> TextPrinter.execute("Hello")
Hello
:ok
使用
此宏允许您在当前模块中注入任何代码。在 use
中使用外部库时应该小心,因为您可能不确定幕后究竟发生了什么。
示例:
defmodule Printer do
defmacro __using__(_opts) do
quote do
def execute(text) do
IO.puts(text)
end
end
end
end
defmodule TextPrinter do
use Printer
end
iex> TextPrinter.execute("Hello")
Hello
:ok
__using__
中的幕后代码已被注入到 TextPrinter
模块中。
By the way, there is more dependency handling instructions in Elixir.
use
和 import
有什么区别?
use is a simple mechanism for using a given module into the current context
https://hexdocs.pm/elixir/Kernel.SpecialForms.html#import/2
Imports function and macros from other modules
看起来有一个区别是 import
让您选择特定的 functions/macros 而 use
将所有内容都包含在内。
还有其他区别吗?你什么时候会用一个而不是另一个?
use
用于将代码注入当前模块,而 import
用于导入函数以供使用。您可以构建一个自动导入函数的 use
实现,例如,当您将 use Timex
添加到模块 take a look at timex.ex if you want to know what I mean 时,我对 Timex 所做的,这是一个如何构建一个非常简单的示例可以 use
'd
import Module
将 Module
的所有函数和宏都以未命名空间的形式引入您的模块。
require Module
允许您使用 Module
的宏,但不导入它们。 (Module
的函数始终可用命名空间。)
use Module
首先是 requires
模块,然后在 Module
.
__using__
宏
考虑以下因素:
defmodule ModA do
defmacro __using__(_opts) do
IO.puts "You are USING ModA"
end
def moda() do
IO.puts "Inside ModA"
end
end
defmodule ModB do
use ModA
def modb() do
IO.puts "Inside ModB"
moda() # <- ModA was not imported, this function doesn't exist
end
end
这将无法编译,因为 ModA.moda()
尚未导入到 ModB
。
以下将通过编译:
defmodule ModA do
defmacro __using__(_opts) do
IO.puts "You are USING ModA"
quote do # <--
import ModA # <--
end # <--
end
def moda() do
IO.puts "Inside ModA"
end
end
defmodule ModB do
use ModA
def modb() do
IO.puts "Inside ModB"
moda() # <-- all good now
end
end
当您 use
d ModA
时,它生成了一个 import
语句,该语句被插入 ModB
.
use Module
需要 Module
并在其上调用 __using__
。
import Module
将 Module
功能引入 当前上下文 ,而不仅仅是需要它。
请参阅 elixir 官方入门指南中的 «alias, require, and import» 页:
# Ensure the module is compiled and available (usually for macros)
require Foo
# Import functions from Foo so they can be called without the `Foo.` prefix
import Foo
# Invokes the custom code defined in Foo as an extension point
use Foo
需要
Elixir 提供宏作为元编程(编写生成代码的代码)的机制。
宏是在编译时执行和扩展的代码块。这意味着,为了使用宏,我们需要保证其模块和实现在编译期间可用。这是通过 require
指令完成的。
一般情况下,一个模块在使用前不需要是必需的,除非我们想使用该模块中可用的宏。
导入
每当我们想在不使用完全限定名称的情况下轻松访问其他模块的函数或宏时,我们都会使用 import
。例如,如果我们想多次使用 List
模块中的 duplicate/2
函数,我们可以导入它:
iex> import List, only: [duplicate: 2]
List
iex> duplicate :ok, 3
[:ok, :ok, :ok]
在这种情况下,我们仅从 List
.
duplicate
(具有 arity 2)
请注意 import
会自动 require
安装一个模块。
使用
虽然不是指令,但 use
是一个与 require
紧密相关的宏,允许您在当前上下文中使用模块。 use
宏经常被开发人员用来将外部功能引入当前词法范围,通常是模块。
在幕后,use
需要给定的模块,然后对其调用 __using__/1
回调,允许模块将一些代码注入当前上下文。一般来说,以下模块:
defmodule Example do
use Feature, option: :value
end
编译成
defmodule Example do
require Feature
Feature.__using__(option: :value)
end
我有 Python/Java/Golang 语言背景,import
与 use
也让我感到困惑。这将通过一些声明性语言示例解释代码重用机制。
导入
简而言之,在 Elixir 中,您不需要导入模块。所有 public 函数都可以通过完全限定的 MODULE.FUNCTION 语法访问:
iex()> Integer.mod(5, 2)
1
iex()> String.trim(" Hello Elixir ")
"Hello Elixir"
在 Python/Java/Golang 中,您需要 import MODULE
才能使用该模块中的功能,例如 Python
In []: import math
In []: math.sqrt(100)
Out[]: 10.0
那么 Elixir 中 import
的功能可能会让您大吃一惊:
We use import whenever we want to easily access functions or macros from other modules without using the fully-qualified name
https://elixir-lang.org/getting-started/alias-require-and-import.html#import
因此,如果您想键入 sqrt
而不是 Integer.sqrt
,trim
而不是 String.trim
,import
会有所帮助
iex()> import Integer
Integer
iex()> sqrt(100)
10.0
iex()> import String
String
iex()> trim(" Hello Elixir ")
"Hello Elixir"
这可能会导致阅读代码时出现问题,并且当存在名称冲突时,它在 Erlang(影响 Elixir 的语言)中是 not recommended。但是 Elixir 中没有这样的约定,您可以自行承担风险。
在Python中,同样的效果可以通过:
from math import *
它只推荐使用 in some special scenarios / 交互模式 - 用于 shorter/faster 打字。
使用和要求
use
/require
的不同之处在于它们与 "macro" 相关 - Python/Java/Golang... 系列中不存在的概念。
你不需要import
一个模块来使用它的功能,但是你需要require
一个模块来使用它的宏:
iex()> Integer.mod(5, 3) # mod is a function
2
iex()> Integer.is_even(42)
** (CompileError) iex:3: you must require Integer before invoking the macro Integer.is_even/1
(elixir) src/elixir_dispatch.erl:97: :elixir_dispatch.dispatch_require/6
iex()> require Integer
Integer
iex()> Integer.is_even(42) # is_even is a macro
true
虽然is_even
可以写成普通函数,但它是一个宏,因为:
In Elixir, Integer.is_odd/1 is defined as a macro so that it can be used as a guard.
https://elixir-lang.org/getting-started/alias-require-and-import.html#require
use
,摘自 Elixir 文档:
use requires the given module and then calls the
__using__/1
callback on it allowing the module to inject some code into the current context.
defmodule Example do
use Feature, option: :value
end
编译成
defmodule Example do
require Feature
Feature.__using__(option: :value)
end
https://elixir-lang.org/getting-started/alias-require-and-import.html#use
所以写use X
和写
require X
X.__using__()
use/2
is a macro,宏会为您将代码转换成其他代码。
你会想要 use MODULE
当你:
- 想要访问其宏 (
require
) - 并执行
MODULE.__using__()
在 Elixir 1.5 上测试
导入
使给定模块中的所有函数和宏都可以在调用它的词法范围内访问。请记住,在大多数情况下,您只需要导入一个或多个 functions/macros。
示例:
defmodule TextPrinter do
import IO, only: [puts: 1]
def execute(text) do
puts(text)
end
end
iex> TextPrinter.execute("Hello")
Hello
:ok
使用
此宏允许您在当前模块中注入任何代码。在 use
中使用外部库时应该小心,因为您可能不确定幕后究竟发生了什么。
示例:
defmodule Printer do
defmacro __using__(_opts) do
quote do
def execute(text) do
IO.puts(text)
end
end
end
end
defmodule TextPrinter do
use Printer
end
iex> TextPrinter.execute("Hello")
Hello
:ok
__using__
中的幕后代码已被注入到 TextPrinter
模块中。
By the way, there is more dependency handling instructions in Elixir.