Elixier: Verwenden Sie vs Import

134

Was ist der Unterschied zwischen useund import?

use ist ein einfacher Mechanismus, um ein bestimmtes Modul im aktuellen Kontext zu verwenden

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

Importiert Funktionen und Makros aus anderen Modulen

Ein Unterschied besteht darin, importdass Sie die spezifischen Funktionen / Makros auswählen und usealles einbringen.

Gibt es noch andere Unterschiede? Wann würden Sie eins über das andere verwenden?

User314159
quelle
Kurzzusammenfassung: import ModuleBringt Funktionen ein, die in Ihrem Modul verwendet werden können. use Modulebringt Funktionen zur Verwendung und macht sie öffentlich auf Ihrem Modul
verfügbar

Antworten:

213

import ModuleBringt alle Funktionen und Makros von Namen ohne Namen Modulein Ihr Modul.

require ModuleErmöglicht die Verwendung von Makros von Module, importiert diese jedoch nicht. (Funktionen von Modulesind immer im Namespace verfügbar.)

use Moduleerstes requiresModul und ruft dann das __using__Makro auf Module.

Folgendes berücksichtigen:

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

Dies wird nicht kompiliert, da ModA.moda()es nicht importiert wurde ModB.

Folgendes wird jedoch kompiliert:

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

Wie , wenn Sie used ModAes erzeugt eine importAnweisung , die in eingefügt wurde ModB.

greggreg
quelle
6
Gute Antwort! Für weitere Informationen: elixir-lang.org/getting-started/alias-require-and-import.html
Justin
Wenn ich zu Elixir komme und aus der Python-Welt komme, bin ich etwas verwirrt darüber, dass die Module *.exDateien und defmoduleBlöcke sind und wie Sie ein Modul aus einer Datei in einen IEX ziehen würden. REPL
Nick T
2
Ich versuche das Beispiel / Konzept zu verstehen. In diesem speziellen Fall demonstrieren Sie nur, dass die __using__Methode ausgeführt wird use ModA? Es wäre wahrscheinlich sinnvoll, nur den Import ModBin dem Beispiel zu verwenden, das Sie richtig dargestellt haben.
Ryan-Neal Mes
35

useist zum Einfügen von Code in das aktuelle Modul vorgesehen, während importFunktionen zum Verwenden importiert werden. Sie können eine useImplementierung erstellen , die Funktionen automatisch importiert, wie ich es beispielsweise mit Timex beim Hinzufügen use Timexzu einem Modul tue. Schauen Sie sich timex.ex an, wenn Sie wissen möchten, was ich meine . Es ist ein sehr einfaches Beispiel für das Erstellen einer Modul, das use'd sein kann

Bitwalker
quelle
1
Ist es also richtig zu sagen, dass usees allgemeiner ist als import? Das heißt, die Funktionalität von importist eine Teilmenge vonuse
User314159
1
importnotwendig ist , noch, wie ich weiß nicht , ob es richtig ist , Sie reimplementieren können zu sagen , importmit useallein, aber ich wäre nicht überrascht, wenn es möglich ist. useist aber absolut mächtiger. Sie können damit sehr komplexe Dinge tun, zum Beispiel verwende ich usein meinem exprotobufProjekt viel davon, was Sie überprüfen können, wenn Sie möchten, dass es an seine Grenzen stößt. Sie können Module mit Code erweitern, Code zur Kompilierungszeit ausführen, einem Modul Funktionen hinzufügen usw. Grundsätzlich werden importMakros kombiniert und die Leistung von Makros.
Bitwalker
Vielen Dank für die ausführliche Erklärung und Verweise auf Code. Ich glaube, ich verstehe es jetzt. Ich bin noch neu bei Elixir, aber ich denke, wenn ich mir mehr Anwendungsfälle anschaue, werden die Unterschiede offensichtlich sein.
User314159
Hey, kein Problem, ein weiterer großartiger Ort wäre das Phoenix-Webframework. Chris McCord hat ein Buch über Elixier-Makros geschrieben und verwendet sie häufig in Phoenix (einschließlich use). Es ist fast definitiv einfacher für Anfänger durchzulesen als exprotobuf, aber ich denke, ich gehe wahrscheinlich usean seine Grenzen, exprotobufso dass es nützlich sein könnte, nur um zu sehen, wie weit man es bringen kann.
Bitwalker
5
usemacht eigentlich nicht viel, es ruft nur __using__das angegebene Modul auf.
Patrick Oscity
25

Siehe die Seite «Alias, erforderlich und importieren» in der offiziellen Anleitung für den Einstieg in das Elixier:

# 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

Benötigen

Elixir bietet Makros als Mechanismus für die Metaprogrammierung (Schreiben von Code, der Code generiert).

Makros sind Codestücke, die zur Kompilierungszeit ausgeführt und erweitert werden. Das heißt, um ein Makro verwenden zu können, müssen wir sicherstellen, dass sein Modul und seine Implementierung während der Kompilierung verfügbar sind. Dies geschieht mit der requireRichtlinie.

Im Allgemeinen muss ein Modul vor der Verwendung nicht benötigt werden, es sei denn, wir möchten die in diesem Modul verfügbaren Makros verwenden.

Importieren

Wir verwenden, importwann immer wir einfach auf Funktionen oder Makros von anderen Modulen zugreifen möchten, ohne den vollständig qualifizierten Namen zu verwenden. Wenn wir beispielsweise die duplicate/2Funktion aus dem ListModul mehrmals verwenden möchten , können wir sie importieren:

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

In diesem Fall importieren wir nur die Funktion duplicate(mit Arität 2) aus List.

Beachten Sie, dass importein Modul automatisch requireaktiviert wird.

Verwenden

Obwohl es sich nicht um eine Direktive handelt, useist ein Makro eng damit verbunden, requiresodass Sie ein Modul im aktuellen Kontext verwenden können. Das useMakro wird häufig von Entwicklern verwendet, um externe Funktionen in den aktuellen lexikalischen Bereich zu integrieren, häufig Module.

Benötigt hinter den Kulissen usedas angegebene Modul und ruft dann den __using__/1Rückruf auf, damit das Modul Code in den aktuellen Kontext einfügen kann. Generell folgendes Modul:

defmodule Example do
  use Feature, option: :value
end

wird kompiliert in

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

Mit Hintergrund aus Python / Java / Golang-Sprachen war das importvs useauch für mich verwirrt. Dies erklärt den Mechanismus der Wiederverwendung von Code anhand einiger Beispiele für deklarative Sprachen.

importieren

Kurz gesagt, in Elixir müssen Sie keine Module importieren. Auf alle öffentlichen Funktionen kann mit der vollqualifizierten Syntax MODULE.FUNCTION zugegriffen werden:

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

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

In Python / Java / Golang müssen Sie, import MODULEbevor Sie Funktionen in diesem MODUL verwenden können, z. B. Python

In []: import math

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

Was importin Elixir dann tut, könnte Sie überraschen:

Wir verwenden den Import immer dann, wenn wir problemlos auf Funktionen oder Makros anderer Module zugreifen möchten, ohne den vollständig qualifizierten Namen zu verwenden

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

Also , wenn Sie möchten , geben Sie sqrtstatt Integer.sqrt, trimstatt String.trim, importwird dazu beitragen ,

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

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

Dies kann zu Problemen beim Lesen von Code führen und wenn es zu Namenskonflikten kommt, wird dies in Erlang (der Sprache, die Elixir beeinflusst) nicht empfohlen . Aber es gibt keine solche Konvention in Elixir, Sie können sie auf eigenes Risiko verwenden.

In Python kann der gleiche Effekt erzielt werden durch:

from math import * 

und es wird nur empfohlen, in einigen speziellen Szenarien / im interaktiven Modus zu verwenden - für kürzeres / schnelleres Tippen.

verwenden & benötigen

Was macht use/ requireunterscheidet ist, dass sie sich auf "Makro" beziehen - das Konzept, das es in der Python / Java / Golang ... -Familie nicht gibt.

Sie benötigen kein importModul, um seine Funktionen zu verwenden, aber Sie benötigen requireein Modul, um seine Makros zu verwenden :

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

Obwohl is_evenes als normale Funktion geschrieben werden kann, ist es ein Makro, weil:

In Elixir ist Integer.is_odd / 1 als Makro definiert, damit es als Schutz verwendet werden kann.

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

use, Auszug aus Elixir doc:

Die Verwendung erfordert das angegebene Modul und ruft dann den __using__/1Rückruf auf, sodass das Modul Code in den aktuellen Kontext einfügen kann.

defmodule Example do
  use Feature, option: :value
end

wird kompiliert in

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

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

Schreiben use Xist also dasselbe wie Schreiben

require X
X.__using__()

use/2 ist ein Makro , Makro wandelt Code in anderen Code für Sie um.

Sie werden wollen, use MODULEwenn Sie:

  • möchte auf seine Makros zugreifen ( require)
  • UND ausführen MODULE.__using__()

Getestet mit Elixir 1.5

HVNSweeting
quelle
3

use Module erfordert Module und ruft __using__es auch auf.

import Modulebringt ModuleFunktionalität in den aktuellen Kontext , erfordert sie nicht nur.

Hagi-Tragger
quelle
0

Importieren

Macht alle Funktionen und Makros eines bestimmten Moduls innerhalb des lexikalischen Bereichs zugänglich, in dem es aufgerufen wird. Beachten Sie, dass in den meisten Fällen nur eine oder mehrere Funktionen / Makros importiert werden müssen.

Beispiel:

defmodule TextPrinter do
  import IO, only: [puts: 1]

  def execute(text) do
    puts(text)
  end
end

iex> TextPrinter.execute("Hello")
Hello
:ok

Verwenden

Mit diesem Makro können Sie beliebigen Code in das aktuelle Modul einfügen. Sie sollten vorsichtig sein, wenn Sie externe Bibliotheken mit verwenden use, da Sie möglicherweise nicht sicher sind, was genau hinter den Kulissen passiert.

Beispiel:

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

Hinter den Kulissen wurde Code __using__in das TextPrinterModul eingefügt.

Übrigens gibt es in Elixir mehr Anweisungen zur Behandlung von Abhängigkeiten .

szsoppa
quelle