tutorial - elixir también se buscó
Elixir: uso vs importación (6)
¿Cuál es la diferencia entre
use
e
import
?
El uso es un mecanismo simple para usar un módulo dado en el contexto actual
https://hexdocs.pm/elixir/Kernel.SpecialForms.html#import/2
Importa funciones y macros de otros módulos
Parece que una diferencia es
import
permite elegir las funciones / macros específicas, mientras que el
use
lo incorpora todo.
¿Hay otras diferencias? ¿Cuándo usarías uno sobre el otro?
Importar
Hace que todas las funciones y macros de un módulo dado sean accesibles dentro del ámbito léxico donde se llama. Tenga en cuenta que, en la mayoría de los casos, solo necesita importar una o más funciones / macros.
Ejemplo:
defmodule TextPrinter do import IO, only: [puts: 1] def execute(text) do puts(text) end end iex> TextPrinter.execute("Hello") Hello :ok
Utilizar
Esta macro le permite inyectar
cualquier
código en el módulo actual.
Debe tener cuidado al usar bibliotecas externas con el
use
, ya que es posible que no esté seguro de lo que sucede exactamente detrás de escena.
Ejemplo:
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
El código detrás de la escena dentro de
__using__
se ha inyectado en el módulo
TextPrinter
.
Por cierto, hay más instrucciones de manejo de dependencias en Elixir .
Con antecedentes de los lenguajes Python / Java / Golang, la
import
vs
use
también fue confusa para mí.
Esto explicará el mecanismo de reutilización de código con algunos ejemplos de lenguajes declarativos.
importar
En resumen, en Elixir, no necesita importar módulos. Se puede acceder a todas las funciones públicas mediante la sintaxis MODULE.FUNCTION completa:
iex()> Integer.mod(5, 2)
1
iex()> String.trim(" Hello Elixir ")
"Hello Elixir"
En Python / Java / Golang, debe
import MODULE
antes de poder usar funciones en ese MÓDULO, por ejemplo, Python
In []: import math
In []: math.sqrt(100)
Out[]: 10.0
Entonces, lo que
import
en Elixir puede sorprenderte:
Usamos importar cuando queremos acceder fácilmente a funciones o macros desde otros módulos sin usar el nombre completo
https://elixir-lang.org/getting-started/alias-require-and-import.html#import
Entonces, si desea escribir
sqrt
lugar de
Integer.sqrt
,
trim
lugar de
String.trim
,
import
le ayudará
iex()> import Integer
Integer
iex()> sqrt(100)
10.0
iex()> import String
String
iex()> trim(" Hello Elixir ")
"Hello Elixir"
Esto puede causar problemas para leer el código y cuando hay un conflicto de nombres, por lo que no se recomienda en Erlang (el idioma que influye en Elixir). Pero no existe tal convención en Elixir, puede usarla bajo su propio riesgo.
En Python, el mismo efecto se puede hacer al:
from math import *
y solo se recomienda usar en algunos escenarios especiales / modo interactivo, para una escritura más corta / más rápida.
usar y requerir
Lo que hace que
use
/
require
diferente es que se relacionan con "macro", el concepto que no existe en Python / Java / Golang ... family.
No necesita
import
un módulo para usar sus funciones, pero necesita un módulo para usar sus 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
Aunque
is_even
puede escribirse como una función normal, es una macro porque:
En Elixir, Integer.is_odd / 1 se define como una macro para que pueda usarse como guardia.
https://elixir-lang.org/getting-started/alias-require-and-import.html#require
use
, para extraer de Elixir doc:
use requiere el módulo dado y luego llama a la devolución
__using__/1
llamada__using__/1
, permitiendo que el módulo inyecte algún código en el contexto actual.
defmodule Example do
use Feature, option: :value
end
se compila en
defmodule Example do
require Feature
Feature.__using__(option: :value)
end
https://elixir-lang.org/getting-started/alias-require-and-import.html#use
Entonces escribir
use X
es lo mismo que escribir
require X
X.__using__()
use/2
es una macro
, la macro transformará el código en otro código para usted.
Deberá
use MODULE
cuando:
-
desea acceder a sus macros (
require
) -
Y ejecute
MODULE.__using__()
Probado en Elixir 1.5
Consulte la página elixir-lang.org/getting-started/alias-require-and-import.html de la guía de inicio oficial de elixir:
# 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
Exigir
Elixir proporciona macros como mecanismo para la metaprogramación (escribir código que genera código).
Las macros son fragmentos de código que se ejecutan y expanden en el momento de la compilación.
Esto significa que, para usar una macro, debemos garantizar que su módulo y su implementación estén disponibles durante la compilación.
Esto se hace con la directiva
require
.
En general, no se necesita un módulo antes del uso, excepto si queremos usar las macros disponibles en ese módulo.
Importar
Usamos
import
siempre que deseamos acceder fácilmente a funciones o macros desde otros módulos sin usar el nombre completo.
Por ejemplo, si queremos usar la función
duplicate/2
del módulo
List
varias veces, podemos importarla:
iex> import List, only: [duplicate: 2]
List
iex> duplicate :ok, 3
[:ok, :ok, :ok]
En este caso, estamos importando solo la función
duplicate
(con arity 2) de
List
.
Tenga en cuenta que la
import
de un módulo lo
require
automáticamente.
Utilizar
Aunque no es una directiva, el
use
es una macro estrechamente relacionada con
require
que le permite usar un módulo en el contexto actual.
Los desarrolladores
use
frecuencia la macro de
use
para incorporar la funcionalidad externa al ámbito léxico actual, a menudo módulos.
Detrás de escena, el
use
requiere el módulo dado y luego llama a la devolución
__using__/1
llamada
__using__/1
, lo que permite que el módulo inyecte algo de código en el contexto actual.
En general, el siguiente módulo:
defmodule Example do
use Feature, option: :value
end
se compila en
defmodule Example do
require Feature
Feature.__using__(option: :value)
end
use
está destinado a inyectar código en el módulo actual, mientras que la
import
se usa para, bueno, importar funciones para su uso.
Puede crear una implementación de
use
que importe automáticamente funciones, por ejemplo, como hago con Timex cuando agrega el
use Timex
a un módulo,
eche un vistazo a timex.ex si desea saber a qué me refiero
, es un ejemplo muy simple de cómo para construir un módulo que se pueda
use
''d
import Module
trae todas las funciones y macros del
Module
sin espacio de nombres en su módulo.
require Module
permite usar macros de
Module
pero no las importa.
(Las funciones del
Module
siempre están disponibles en espacios de nombres).
use Module
primero
requires
módulo y luego llama a la macro
__using__
en el
Module
.
Considera lo siguiente:
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
Esto no se compilará ya que
ModA.moda()
no se ha importado a
ModB
.
Sin embargo, se compilará lo siguiente:
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
Como cuando
use
d
ModA
, generó una declaración de
import
que se insertó en
ModB
.
use Module
requiere
Module
y también invoca
__using__
en él.
import Module
trae la funcionalidad del
Module
al
contexto actual
, no solo lo requiere.