Elixir:使用vs import

时间:2015-02-13 01:56:08

标签: elixir

useimport之间的区别是什么?

  

use是一种将给定模块用于当前上下文的简单机制

https://hexdocs.pm/elixir/Kernel.SpecialForms.html#import/2

  

从其他模块导入函数和宏

看起来有一个区别是import让你挑选出特定的功能/宏,而use会带来一切。

还有其他差异吗?你什么时候用一个而不是另一个?

6 个答案:

答案 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.sqrttrim而不是String.trimimport会有所帮助

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 /交互模式 - 用于更短/更快的输入。

使用&amp;需要

使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