Elixir: gunakan vs impor

134

Apa perbedaan antara usedan import?

Penggunaan adalah mekanisme sederhana untuk menggunakan modul yang diberikan ke dalam konteks saat ini

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

Mengimpor fungsi dan makro dari modul lain

Sepertinya satu perbedaannya adalah importmari kita memilih fungsi / makro tertentu sambil usememasukkan semuanya.

Apakah ada perbedaan lain? Kapan Anda akan menggunakan satu di atas yang lain?

Pengguna314159
sumber
Ringkasan cepat: import Modulemembawa fungsi untuk digunakan di dalam modul Anda. use Modulemembawa fungsi yang akan digunakan DAN memaparkannya di depan umum pada modul Anda
Jered

Jawaban:

213

import Modulemembawa semua Fungsi dan Makro Moduleun-namespaced ke dalam modul Anda.

require Modulememungkinkan Anda untuk menggunakan makro Moduletetapi tidak mengimpornya. (Fungsi Moduleselalu tersedia namespace.)

use Modulerequiresmodul pertama dan kemudian memanggil __using__makro aktif Module.

Pertimbangkan yang berikut ini:

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

Ini tidak akan dikompilasi karena ModA.moda()belum diimpor ke ModB.

Berikut ini akan dikompilasi:

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

Seperti ketika Anda used ModAitu dihasilkan importpernyataan yang dimasukkan ke dalam ModB.

greggreg
sumber
6
Jawaban bagus! Untuk info lebih lanjut: elixir-lang.org/getting-started/alias-require-and-import.html
justin
Masuk ke Elixir, dan dari dunia Python saya agak bingung tentang modul menjadi *.exfile dan defmoduleblok, dan bagaimana Anda akan menarik modul dari file ke iex REPL
Nick T
2
Mencoba memahami contoh / konsepnya. Dalam kasus khusus ini Anda hanya menunjukkan bahwa __using__metode ini dijalankan use ModA? Mungkin masuk akal untuk hanya menggunakan impor dalam ModBcontoh yang Anda berikan benar?
Ryan-Neal Mes
35

usedimaksudkan untuk menyuntikkan kode ke modul saat ini, sementara importdigunakan untuk, yah, mengimpor fungsi untuk digunakan. Anda dapat membangun useimplementasi yang secara otomatis mengimpor fungsi misalnya, seperti yang saya lakukan dengan Timex ketika Anda menambahkan use Timexke modul, lihat timex.ex jika Anda ingin tahu apa yang saya maksud , itu adalah contoh yang sangat sederhana tentang bagaimana membangun sebuah modul yang dapat berupa use'd

bitwalker
sumber
1
Jadi, apakah akurat mengatakan uselebih umum daripada import? Artinya, fungsi dari importadalah bagian dariuse
User314159
1
importmasih perlu, karena saya tidak tahu apakah itu akurat untuk mengatakan Anda dapat menerapkan kembali importdengan usesendirian, tetapi saya tidak akan terkejut jika itu mungkin. usebenar-benar lebih kuat. Anda dapat melakukan hal-hal yang sangat rumit dengannya, misalnya, saya menggunakan banyak usedalam exprotobufproyek saya yang dapat Anda periksa jika Anda ingin melihatnya didorong ke batas itu. Anda dapat memperluas modul dengan kode, mengeksekusi kode pada waktu kompilasi, menambahkan fungsi ke modul, dll. Pada dasarnya menggabungkan importdan kekuatan makro.
bitwalker
terima kasih atas penjelasan terperinci dan referensi kode. Saya rasa saya mengerti sekarang. Saya masih baru untuk Elixir tapi saya pikir begitu saya melihat lebih banyak kasus penggunaan, perbedaannya akan jelas.
User314159
Hai, tidak masalah, tempat bagus lain untuk dilihat adalah kerangka web Phoenix. Chris McCord telah menulis sebuah buku tentang macro Elixir, dan dia banyak menggunakannya di Phoenix (termasuk use). Hampir pasti lebih mudah untuk membaca untuk pemula daripada exprotobuf, tapi saya pikir saya mungkin mendorong useke batas exprotobufsehingga mungkin berguna hanya untuk melihat seberapa jauh Anda bisa mengambilnya.
bitwalker
5
usesebenarnya tidak berbuat banyak, itu hanya memanggil __using__modul yang ditentukan.
Patrick Oscity
25

Lihat halaman «alias, perlu, dan impor» dari panduan memulai resmi 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

Memerlukan

Elixir menyediakan makro sebagai mekanisme untuk meta-pemrograman (menulis kode yang menghasilkan kode).

Makro adalah potongan kode yang dieksekusi dan diperluas pada waktu kompilasi. Ini berarti, untuk menggunakan makro, kita perlu menjamin modulnya dan implementasinya tersedia selama kompilasi. Ini dilakukan dengan requirearahan.

Secara umum, sebuah modul tidak perlu diminta sebelum digunakan, kecuali jika kita ingin menggunakan makro yang tersedia dalam modul itu.

Impor

Kami menggunakan importkapan pun kami ingin dengan mudah mengakses fungsi atau makro dari modul lain tanpa menggunakan nama yang sepenuhnya memenuhi syarat. Sebagai contoh, jika kita ingin menggunakan duplicate/2fungsi dari Listmodul beberapa kali, kita dapat mengimpornya:

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

Dalam hal ini, kami hanya mengimpor fungsi duplicate(dengan arity 2) dari List.

Perhatikan bahwa importmodul secara otomatis require.

Menggunakan

Meskipun bukan arahan, useadalah makro terkait erat requireyang memungkinkan Anda untuk menggunakan modul dalam konteks saat ini. The usemakro sering digunakan oleh pengembang untuk membawa fungsi eksternal ke dalam lingkup leksikal saat ini, sering modul.

Di belakang layar, usememerlukan modul yang diberikan dan kemudian memanggil __using__/1callback di atasnya memungkinkan modul untuk menyuntikkan beberapa kode ke dalam konteks saat ini. Secara umum, modul berikut:

defmodule Example do
  use Feature, option: :value
end

dikompilasi menjadi

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

Dengan latar belakang dari bahasa Python / Java / Golang, importvs useitu juga membingungkan bagi saya. Ini akan menjelaskan mekanisme penggunaan kembali kode dengan beberapa contoh bahasa deklaratif.

impor

Singkatnya, di Elixir, Anda tidak perlu mengimpor modul. Semua fungsi publik dapat diakses dengan sintaks MODULE.FUNCTION yang memenuhi syarat:

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

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

Dalam Python / Java / Golang, Anda perlu import MODULEsebelum Anda dapat menggunakan fungsi dalam MODULE itu, misalnya Python

In []: import math

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

Lalu apa yang importdilakukan Elixir mungkin mengejutkan Anda:

Kami menggunakan impor kapan pun kami ingin dengan mudah mengakses fungsi atau makro dari modul lain tanpa menggunakan nama yang sepenuhnya memenuhi syarat

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

Jadi jika Anda ingin mengetik sqrtbukan Integer.sqrt, trimbukan String.trim, importakan membantu

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

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

Ini dapat menyebabkan masalah untuk membaca kode dan ketika ada pertentangan nama sehingga tidak direkomendasikan dalam Erlang (bahasa yang memengaruhi Elixir). Tetapi tidak ada konvensi semacam itu di Elixir, Anda dapat menggunakannya dengan risiko sendiri.

Dalam Python, efek yang sama dapat dilakukan oleh:

from math import * 

dan itu hanya disarankan untuk digunakan dalam beberapa skenario khusus / mode interaktif - untuk pengetikan yang lebih pendek / lebih cepat.

gunakan & butuhkan

Apa yang membuat use/ requireberbeda adalah bahwa mereka berhubungan dengan "makro" - konsep yang tidak ada dalam keluarga Python / Java / Golang ....

Anda tidak perlu importmodul untuk menggunakan fungsinya, tetapi Anda perlu requiremodul untuk menggunakan makro :

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

Meskipun is_evendapat ditulis sebagai fungsi normal, ini adalah makro karena:

Dalam Elixir, Integer.is_odd / 1 didefinisikan sebagai makro sehingga dapat digunakan sebagai pelindung.

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

use, untuk kutipan dari Elixir doc:

Penggunaan membutuhkan modul yang diberikan dan kemudian memanggil __using__/1callback di atasnya memungkinkan modul untuk menyuntikkan beberapa kode ke dalam konteks saat ini.

defmodule Example do
  use Feature, option: :value
end

dikompilasi menjadi

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

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

Jadi menulis use Xsama dengan menulis

require X
X.__using__()

use/2 adalah makro , makro akan mengubah kode menjadi kode lain untuk Anda.

Anda akan ingin use MODULEketika Anda:

  • ingin mengakses makronya ( require)
  • DAN jalankan MODULE.__using__()

Diuji pada Elixir 1.5

HVNMencintai
sumber
3

use Module membutuhkan Module dan juga memanggilnya __using__.

import Modulemembawa Modulefungsionalitas ke dalam konteks saat ini , bukan hanya membutuhkannya.

hagi-tragger
sumber
0

Impor

Membuat semua fungsi dan makro dari modul yang diberikan dapat diakses di dalam lingkup leksikal tempat namanya. Perlu diingat bahwa dalam kebanyakan kasus Anda hanya perlu satu fungsi / makro yang akan diimpor.

Contoh:

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

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

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

Menggunakan

Makro ini memungkinkan Anda untuk menyuntikkan kode apa pun dalam modul saat ini. Anda harus berhati-hati ketika menggunakan perpustakaan eksternal dengan use, karena Anda mungkin tidak yakin apa yang sebenarnya terjadi di balik layar.

Contoh:

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

Di belakang kode adegan di dalam __using__telah disuntikkan ke dalam TextPrintermodul.

Omong-omong, ada lebih banyak instruksi penanganan ketergantungan dalam Elixir .

szsoppa
sumber