use
和import
之间的区别是什么?
use是一种将给定模块用于当前上下文的简单机制
https://hexdocs.pm/elixir/Kernel.SpecialForms.html#import/2
从其他模块导入函数和宏
看起来有一个区别是import
让你挑选出特定的功能/宏,而use
会带来一切。
还有其他差异吗?你什么时候用一个而不是另一个?
答案 0 :(得分:174)
import Module
将Module
非命名空间的所有函数和宏带入您的模块。
require Module
允许您使用Module
的宏,但不会导入它们。 (Module
的函数始终可用命名空间。)
use Module
第一个requires
模块,然后调用__using__
上的Module
宏。
请考虑以下事项:
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
。
答案 1 :(得分:27)
use
用于将代码注入当前模块,而import
用于导入要使用的函数。您可以构建一个自动导入函数的use
实现,就像我在向模块take a look at timex.ex if you want to know what I mean添加use Timex
时使用Timex一样,它是一个非常简单的示例构建一个可以use
&#39; d
答案 2 :(得分:16)
请参阅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
。例如,如果我们想多次使用duplicate/2
模块中的List
函数,我们可以导入它:
iex> import List, only: [duplicate: 2]
List
iex> duplicate :ok, 3
[:ok, :ok, :ok]
在这种情况下,我们只从duplicate
导入函数List
(带有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
答案 3 :(得分:10)
使用Python / Java / Golang语言的背景,import
vs use
对我来说也很困惑。这将解释代码重用机制与一些声明性语言的例子。
简而言之,在Elixir中,您不需要导入模块。所有公共函数都可以通过完全限定的MODULE.FUNCTION语法访问:
iex()> Integer.mod(5, 2)
1
iex()> String.trim(" Hello Elixir ")
"Hello Elixir"
在Python / Java / Golang中,您需要import MODULE
才能使用该MODULE中的函数,例如Python
In []: import math
In []: math.sqrt(100)
Out[]: 10.0
那么Elixir中的import
可能会让你感到惊讶:
每当我们想要在不使用完全限定名称的情况下轻松访问其他模块的函数或宏时,我们就会使用import
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 /交互模式 - 用于更短/更快的输入。
使use
/ require
与众不同的是它们与“宏”有关 - 这是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
可以写为普通函数,但它是一个宏,因为:
在Elixir中,Integer.is_odd / 1被定义为一个宏,因此它可以用作一个守卫。
https://elixir-lang.org/getting-started/alias-require-and-import.html#require
use
,摘自Elixir doc:
use需要给定模块,然后调用它上面的
__using__/1
回调,允许模块将一些代码注入当前上下文。
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上测试
答案 4 :(得分:1)
use Module
需要 Module
并在其上调用__using__
。
import Module
将Module
功能带入当前上下文,而不仅仅是需要它。
答案 5 :(得分:0)
使给定模块中的所有函数和宏都可以在调用它的词法范围内访问。请记住,在大多数情况下,只需要导入一个或多个函数/宏即可。
示例:
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。