web-dev-qa-db-fra.com

Elixir: utilisation vs importation

Quelle est la différence entre use et import?

use est un mécanisme simple pour utiliser un module donné dans le contexte actuel

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

Importe des fonctions et des macros à partir d'autres modules

On dirait que la différence est que import vous laisse choisir les fonctions/macros spécifiques alors que use apporte tout ce qu'il faut.

Y a-t-il d'autres différences? Quand utiliseriez-vous l'un sur l'autre?

120
User314159

import Module apporte toutes les fonctions et macros de Module non-namespaced dans votre module.

require Module vous permet d'utiliser des macros de Module mais ne les importe pas. (Les fonctions de Module sont toujours disponibles en espacement de noms.)

use Module d'abord requires module puis appelle la macro __using__ Sur Module.

Considérer ce qui suit:

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

Cela ne compilera pas car ModA.moda() n'a pas été importé dans ModB.

Ce qui suit va compiler si:

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

Comme lorsque vous used ModA, il a généré une instruction import qui a été insérée dans ModB.

183
greggreg

use est destiné à l'injection de code dans le module actuel, tandis que import est utilisé pour importer des fonctions à utiliser. Vous pouvez construire une implémentation use qui importe automatiquement des fonctions, comme je le fais avec Timex lorsque vous ajoutez use Timex vers un module, jetez un coup d’œil à timex.ex si vous voulez savoir ce que je veux dire , c’est un exemple très simple de la construction d’un module qui peut être use ' ré

29
bitwalker

Voir "alias, require et import" page du guide de prise en main de l'élixir officiel:

# 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

Exiger

Elixir fournit des macros comme mécanisme de méta-programmation (écriture de code générant du code).

Les macros sont des fragments de code exécutés et développés au moment de la compilation. Cela signifie que pour utiliser une macro, nous devons nous assurer que son module et son implémentation sont disponibles lors de la compilation. Ceci est fait avec la directive require.

En général, un module n'a pas besoin d'être requis avant l'utilisation, sauf si nous voulons utiliser les macros disponibles dans ce module.

Importation

Nous utilisons import chaque fois que nous voulons accéder facilement à des fonctions ou à des macros à partir d'autres modules sans utiliser le nom complet. Par exemple, si nous voulons utiliser le duplicate/2 fonction du module List plusieurs fois, nous pouvons l’importer:

iex> import List, only: [duplicate: 2]
List
iex> duplicate :ok, 3
[:ok, :ok, :ok]

Dans ce cas, nous importons uniquement la fonction duplicate (avec l'arité 2) depuis List.

Notez que importing un module automatiquement _ requires.

Utilisation

Bien que n'étant pas une directive, use est une macro étroitement liée à require qui vous permet d'utiliser un module dans le contexte actuel. La macro use est fréquemment utilisée par les développeurs pour intégrer des fonctionnalités externes dans la portée lexicale actuelle, souvent des modules.

En coulisse, use nécessite le module donné, puis appelle le __using__/1 callback permettant au module d’injecter du code dans le contexte actuel. De manière générale, le module suivant:

defmodule Example do
  use Feature, option: :value
end

est compilé dans

defmodule Example do
  require Feature
  Feature.__using__(option: :value)
end
18
fetsh

Avec des antécédents issus des langages Python/Java/Golang, le import vs use était également confus pour moi. Cela expliquera le mécanisme de réutilisation du code avec des exemples de langages déclaratifs.

importation

En bref, dans Elixir, vous n'avez pas besoin d'importer des modules. Toutes les fonctions publiques sont accessibles avec la syntaxe qualifiée complète de MODULE.FUNCTION:

iex()> Integer.mod(5, 2)
1

iex()> String.trim(" Hello Elixir  ")
"Hello Elixir"

En Python/Java/Golang, vous devez import MODULE Pour pouvoir utiliser les fonctions de ce MODULE, par exemple Python.

In []: import math

In []: math.sqrt(100)
Out[]: 10.0

Alors ce que import dans Elixir pourrait vous surprendre:

Nous utilisons import chaque fois que nous voulons accéder facilement à des fonctions ou à des macros à partir d'autres modules sans utiliser le nom complet

https://elixir-lang.org/getting-started/alias-require-and-import.html#import

Donc, si vous voulez taper sqrt au lieu de Integer.sqrt, trim au lieu de String.trim, import aidera

iex()> import Integer
Integer
iex()> sqrt(100)
10.0

iex()> import String
String
iex()> trim(" Hello Elixir    ")
"Hello Elixir"

Cela pourrait poser des problèmes pour la lecture du code et en cas de conflit de noms, il est donc non recommandé en Erlang (la langue qui influence Elixir). Mais il n’existe pas de convention de ce type chez Elixir, vous pouvez l’utiliser à vos risques et périls.

En Python, le même effet peut être obtenu par:

from math import * 

et il a seulement recommandé d'utiliser dans certains scénarios spéciaux /mode interactif - pour une frappe plus courte/plus rapide.

utiliser et exiger

La différence entre use/require est qu’elles ont trait à la "macro" - concept qui n’existe pas dans la famille Python/Java/Golang ....

Vous n'avez pas besoin de import un module pour utiliser ses fonctions, mais vous devez require d'un module pour utiliser ses 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

Bien que is_even Puisse être écrit comme une fonction normale, il s’agit d’une macro parce que:

Dans Elixir, Integer.is_odd/1 est défini en tant que macro pour pouvoir être utilisé en tant que garde.

https://elixir-lang.org/getting-started/alias-require-and-import.html#require

use, extrait de la documentation Elixir:

use requiert le module donné, puis appelle le rappel __using__/1 dessus, permettant ainsi au module d'injecter du code dans le contexte actuel.

defmodule Example do
  use Feature, option: :value
end

est compilé dans

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

https://elixir-lang.org/getting-started/alias-require-and-import.html#use

Donc, écrire use X Revient à écrire

require X
X.__using__()

use/2est une macro , la macro transformera le code en un autre code pour vous.

Vous voudrez use MODULE Quand vous:

  • vouloir accéder à ses macros (require)
  • ET exécuter MODULE.__using__()

Testé sur Elixir 1.5

11
HVNSweeting

use Module requiert Module et appelle également __using__ dessus.

import Module introduit la fonctionnalité Module dans le contexte actuel et ne l’impose pas seulement.

3
hagi-tragger