Elisir: usa vs importazione


134

Qual è la differenza tra usee import?

use è un semplice meccanismo per utilizzare un determinato modulo nel contesto corrente

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

Importa la funzione e le macro da altri moduli

Sembra che una differenza sia quella importdi scegliere le specifiche funzioni / macro mentre useporta tutto dentro.

Ci sono altre differenze? Quando useresti l'uno sopra l'altro?


Riepilogo rapido: import Moduleintroduce le funzioni da utilizzare all'interno del modulo. use Moduleporta le funzioni da usare E le espone pubblicamente sul tuo modulo
Jered

Risposte:


213

import Moduleporta tutte le funzioni e le macro di Moduleun-namespace nel tuo modulo.

require Moduleti permette di usare le macro Modulema non le importa. (Le funzioni di Modulesono sempre disponibili nello spazio dei nomi.)

use Moduleprimo requiresmodulo e quindi chiama la __using__macro Module.

Considera quanto segue:

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

Questo non verrà compilato come ModA.moda()non è stato importato in ModB.

Verrà comunque compilato quanto segue:

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

Come quando si useD ModAha generato una importdichiarazione che è stata inserita ModB.


6
Bella risposta! Per maggiori informazioni: elixir-lang.org/getting-started/alias-require-and-import.html
justin

Entrando in Elixir, ed essendo dal mondo Python, sono un po 'confuso riguardo ai moduli che sono *.exfile e defmoduleblocchi, e al modo in cui tireresti un modulo da un file in un REPL iex
Nick T

2
Cercare di capire l'esempio / concetto. In questo caso particolare stai solo dimostrando che il __using__metodo è eseguito use ModA? Probabilmente avrebbe senso usare semplicemente import ModBnell'esempio che hai presentato correttamente?
Ryan-Neal Mes

35

useè inteso per l'iniezione di codice nel modulo corrente, mentre importè usato per importare funzioni per l'uso. Puoi creare useun'implementazione che importa automaticamente le funzioni, ad esempio, come faccio con Timex quando aggiungi use Timexa un modulo, dai un'occhiata a timex.ex se vuoi sapere cosa intendo , è un esempio molto semplice di come costruire un modulo che può essere use'd


1
Quindi è corretto dire che useè più generale di import? Cioè, la funzionalità di importè un sottoinsieme diuse
User314159

1
importè ancora necessario, poiché non so se sia corretto dire che puoi reimplementarlo importda usesolo, ma non sarei sorpreso se fosse possibile. useè assolutamente più potente però. Puoi fare cose molto complesse con esso, ad esempio, usenel mio exprotobufprogetto faccio un uso intensivo che potresti verificare se vuoi vederlo spinto al limite. È possibile estendere i moduli con il codice, eseguire il codice in fase di compilazione, aggiungere funzioni a un modulo, ecc. Fondamentalmente combina importe la potenza delle macro.
Bitwalker,

grazie per la spiegazione dettagliata e riferimenti al codice. Penso di averlo capito adesso. Sono ancora nuovo di Elisir ma penso che una volta esaminati più casi d'uso le differenze saranno evidenti.
User314159,

Ehi nessun problema, un altro ottimo posto dove guardare sarebbe il web framework Phoenix. Chris McCord ha scritto un libro sulle macro di elisir e le usa pesantemente a Phoenix (incluso use). È quasi sicuramente più facile da leggere per un principiante rispetto a exprotobuf, ma penso che probabilmente spingerò useal limite in exprotobufmodo che possa essere utile solo per vedere fino a dove puoi portarlo.
Bitwalker,

5
usein realtà non fa molto, chiama solo __using__il modulo specificato.
Patrick Oscity,

25

Vedi la pagina «alias, richiedi e importa» dalla guida introduttiva ufficiale dell'elisir:

# 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

richiedere

L'elisir fornisce macro come meccanismo per la meta-programmazione (scrittura di codice che genera codice).

Le macro sono blocchi di codice che vengono eseguiti ed espansi al momento della compilazione. Ciò significa che, per usare una macro, dobbiamo garantire che il suo modulo e l'implementazione siano disponibili durante la compilazione. Questo viene fatto con la requiredirettiva.

In generale, non è necessario richiedere un modulo prima dell'uso, tranne se si desidera utilizzare le macro disponibili in quel modulo.

Importare

Usiamo importogni volta che vogliamo accedere facilmente alle funzioni o alle macro da altri moduli senza usare il nome completo. Ad esempio, se vogliamo utilizzare la duplicate/2funzione dal Listmodulo più volte, possiamo importarla:

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

In questo caso, stiamo importando solo la funzione duplicate(con arity 2) da List.

Si noti che importing un modulo è automaticamente require.

Uso

Sebbene non sia una direttiva, useè una macro strettamente correlata a requirequella che consente di utilizzare un modulo nel contesto corrente. La usemacro viene spesso utilizzata dagli sviluppatori per portare funzionalità esterne nell'attuale ambito lessicale, spesso moduli.

Dietro le quinte, userichiede il modulo dato e quindi chiama il __using__/1callback su di esso consentendo al modulo di iniettare un po 'di codice nel contesto corrente. In generale, il seguente modulo:

defmodule Example do
  use Feature, option: :value
end

è compilato in

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

14

Con lo sfondo dalle lingue Python / Java / Golang, anche il importvs è usestato confuso per me. Questo spiegherà il meccanismo di riutilizzo del codice con alcuni esempi di linguaggi dichiarativi.

importare

In breve, in Elisir, non è necessario importare moduli. Tutte le funzioni pubbliche sono accessibili dalla sintassi MODULE.FUNCTION completa:

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

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

In Python / Java / Golang, è necessario import MODULEprima di poter utilizzare le funzioni in quel MODULO, ad esempio Python

In []: import math

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

Quindi ciò che importfa Elisir potrebbe sorprenderti:

Usiamo import ogni volta che vogliamo accedere facilmente a funzioni o macro da altri moduli senza usare il nome completo

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

Quindi, se si desidera digitare sqrtanziché Integer.sqrt, trimanziché String.trim, importsarà di aiuto

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

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

Ciò potrebbe causare problemi nella lettura del codice e in caso di conflitto di nomi, quindi non è raccomandato in Erlang (la lingua che influenza l'Elisir). Ma non esiste una convenzione del genere in Elisir, puoi usarlo a proprio rischio.

In Python, lo stesso effetto può essere fatto da:

from math import * 

e si consigliava di utilizzare solo in alcuni scenari speciali / modalità interattiva - per una digitazione più breve / più veloce.

usare e richiedere

Ciò che rende use/ requirediverso è che si riferiscono alla "macro" - il concetto che non esiste nella famiglia Python / Java / Golang ...

Non è necessario che importun modulo utilizzi le sue funzioni, ma è necessario che requireun modulo utilizzi le sue macro :

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

Sebbene is_evenpossa essere scritto come una normale funzione, è una macro perché:

In Elisir, Integer.is_odd / 1 è definito come una macro in modo che possa essere usato come guardia.

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

use, per estrarre dal documento Elisir:

use richiede il modulo dato e quindi chiama il __using__/1callback su di esso consentendo al modulo di iniettare del codice nel contesto corrente.

defmodule Example do
  use Feature, option: :value
end

è compilato in

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

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

Quindi scrivere use Xè come scrivere

require X
X.__using__()

use/2 è una macro , la macro trasformerà il codice in un altro codice per te.

Lo vorrai use MODULEquando:

  • vuoi accedere alle sue macro ( require)
  • E eseguire MODULE.__using__()

Testato su Elisir 1.5


3

use Module richiede Module e lo chiama anche __using__.

import Moduleporta la Modulefunzionalità nel contesto attuale , non solo la richiede.


0

Importare

Rende accessibili tutte le funzioni e le macro da un determinato modulo all'interno dell'ambito lessicale in cui viene chiamato. Tenere presente che nella maggior parte dei casi è necessario importare solo una o più funzioni / macro.

Esempio:

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

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

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

Uso

Questa macro consente di iniettare qualsiasi codice nel modulo corrente. Dovresti stare attento quando usi le librerie esterne con use, poiché potresti non essere sicuro di cosa succede esattamente dietro le quinte.

Esempio:

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

Dietro il codice scena all'interno di __using__è stato iniettato nel TextPrintermodulo.

A proposito, ci sono più istruzioni per la gestione delle dipendenze in Elisir .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.