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?
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 use
d ModA
, il a généré une instruction import
qui a été insérée dans ModB
.
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é
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
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.
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 import
ing un module automatiquement _ require
s.
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
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.
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.
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/2
est une macro , la macro transformera le code en un autre code pour vous.
Vous voudrez use MODULE
Quand vous:
require
)MODULE.__using__()
Testé sur Elixir 1.5
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.