首页 文章

Elixir:使用vs import

提问于
浏览
108

useimport 之间有什么区别?

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

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

从其他模块导入函数和宏

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

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

5 回答

  • 26

    import ModuleModule un-namespaced的所有函数和宏带入模块 .

    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 它生成一个插入 ModBimport 语句 .

  • 161

    use 用于将代码注入当前模块,而 import 用于导入要使用的函数 . 您可以构建一个自动导入函数的 use 实现,就像我将 use Timex 添加到模块时使用Timex一样,take a look at timex.ex if you want to know what I mean,这是一个非常简单的示例,说明如何构建一个可以 use d的模块 .

  • 1

    请参阅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 s .

    使用

    虽然不是指令, use 是一个与 require 紧密相关的宏,它允许您在当前上下文中使用模块 . 开发人员经常使用 use 宏将外部功能引入当前的词法范围,通常是模块 .

    在幕后, use 需要给定模块,然后在其上调用 __using__/1 回调,允许模块将一些代码注入当前上下文 . 一般来说,以下模块:

    defmodule Example do
      use Feature, option: :value
    end
    

    编译成

    defmodule Example do
      require Feature
      Feature.__using__(option: :value)
    end
    
  • 14

    有了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 /交互模式 - 用于更短/更快的打字 .

    使用和要求

    使 use / require 与众不同的是它们与"macro"有关 - 这是Python / Java / Golang ...系列中不存在的概念 .

    You don't need to import a module to use its functions, but you need to require a module to use its macros

    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上测试

  • 8

    use Module 需要 Module 和也打电话给 __using__ .

    import ModuleModule 功能带入当前上下文,而不仅仅是需要它 .

相关问题