İksir: İçe aktarmaya karşı kullanın


135

Arasındaki fark nedir useve import?

kullanım, belirli bir modülü mevcut bağlamda kullanmak için basit bir mekanizmadır

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

Diğer modüllerden işlevi ve makroları içe aktarır

Görünüşe göre bir fark, importbelirli işlevleri / makroları seçip useher şeyi içeri getirmenize izin verelim .

Başka farklılıklar var mı? Birini diğerine ne zaman kullanırsın?


Hızlı özet: import Modulemodülünüzde kullanılacak işlevleri getirir. use Modulekullanılacak işlevleri getirir VE bunları modülünüzde herkese açık olarak gösterir
Jered

Yanıtlar:


213

import Moduleisimsiz tüm Fonksiyonları ve Makroları Modulemodülünüze getirir.

require Modulemakro kullanmanıza izin verir Moduleancak bunları içe aktarmaz. (İşlevleri Moduleher zaman ad alanlıdır.)

use Moduleilk requiresmodül ve ardından __using__makroyu çağırır Module.

Aşağıdakileri göz önünde bulundur:

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

Bu, ModA.moda()içine aktarılmadığı gibi derlenmeyecektir ModB.

Aşağıdakiler yine de derlenecektir:

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

Eğer zaman olduğu gibi used ModAbir oluşturulmuş importyerleştirildi deyimi ModB.


6
Mükemmel cevap! Daha fazla bilgi için: elixir-lang.org/getting-started/alias-require-and-import.html
justin

Elixir'e girmek ve Python dünyasından olmak, modüllerin *.exdosyalar ve defmodulebloklar olduğu ve bir modülü bir dosyadan iex REPL'e nasıl çekeceğiniz konusunda kafam karıştı
Nick T

2
Örnek / kavramı anlamaya çalışıyorum. Bu özel durumda, sadece __using__yöntemin çalıştırıldığını use ModAmı gösteriyorsunuz? ModBDoğru sunduğunuz örnekte içe aktarımı kullanmak muhtemelen mantıklı olur mu?
Ryan-Neal Mes

35

usekodun mevcut modüle enjekte edilmesi amaçlanırken import, işlevlerin kullanım için içe aktarılması için kullanılır. Bir inşa edebilirsiniz useeklediğinizde ben Timex ile yaptığı gibi, uygulama örneğin otomatik ithalat fonksiyonları use Timexbir modüle, ne demek istediğimi bilmek istiyorsanız timex.ex bakmak , bir nasıl oluşturulacağını çok basit bir örnek modül use'd olabilir


1
Öyleyse usedaha genel olduğunu söylemek doğru importmu? Yani, işlevinin importbir alt kümesidiruse
Kullanıcı314159

1
importBen bunu reimplement söylemek pek doğru olmadığını bilmiyorum olarak, hala gereklidir importile useyalnız ama eğer mümkünse ben şaşırmayacağım. usekesinlikle daha güçlüdür. Bunları, örneğin, ben ağır faydalanmak, onunla çok karmaşık şeyler yapabilirsiniz usebenim de exprotobufbunu 's sınırlarına itti görmek istiyorsanız size kontrol edebilir proje. Modülleri kodla genişletebilir, derleme sırasında kod çalıştırabilir, bir modüle işlevler ekleyebilir, vb. Temelde importmakroların gücünü ve birleştirir .
bitwalker

ayrıntılı açıklama ve kod referansları için teşekkür ederiz. Sanırım şimdi anladım. Elixir'de hala yeniyim ama sanırım daha fazla kullanım durumuna baktığımda farklılıklar bariz olacak.
User314159

Sorun değil, bakılacak başka bir harika yer de Phoenix web çerçevesi olabilir. Chris McCord, Elixir makroları hakkında bir kitap yazdı ve bunları Phoenix'te (dahil use) yoğun bir şekilde kullanıyor . Yeni başlayanlar için okuması neredeyse kesinlikle daha kolay exprotobuf, ama sanırım muhtemelen usesınırını zorluyorum , bu exprotobufyüzden ne kadar ileri gidebileceğini görmek faydalı olabilir.
bitwalker

5
useaslında pek bir şey yapmaz, sadece __using__belirtilen modülü çağırır .
Patrick Oscity

25

Bkz «diğer adı gerektirir ve ithalat» iksir görevlisinden sayfa başlarken kılavuzu:

# 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

gerektir

Elixir, bir meta programlama mekanizması olarak makrolar sağlar (kod üreten kod yazma).

Makrolar, derleme zamanında çalıştırılan ve genişletilen kod parçalarıdır. Bu, bir makro kullanmak için, modülünün ve uygulamasının derleme sırasında kullanılabilir olmasını garanti etmemiz gerektiği anlamına gelir. Bu requireyönerge ile yapılır .

Genel olarak, o modülde bulunan makroları kullanmak istememiz dışında, kullanımdan önce bir modüle ihtiyaç duyulmaz.

İthalat

Biz kullanmak importistediğimiz zaman tam nitelikli adını kullanmadan kolayca erişim fonksiyonları veya diğer modüllerden makrolarına. Örneğin duplicate/2, Listmodülden işlevi birkaç kez kullanmak istersek, onu içe aktarabiliriz:

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

Bu durumda, duplicatekaynağından sadece (arity 2 ile) fonksiyonu içe aktarıyoruz List.

importBir modülün otomatik olarak oluşturulduğunu unutmayın require.

kullanım

Yönerge olmasa da , mevcut bağlamda bir modülü kullanmanıza izin veren usebir makrodur require. useMakro sıklıkla genellikle geçerli sözcük kapsam içine modülleri dış işlevler kazandırmak için geliştiriciler tarafından kullanılıyor.

Perde arkasında, useverilen modülü gerektirir ve ardından __using__/1geri aramayı çağırarak modülün mevcut içeriğe bir miktar kod enjekte etmesini sağlar. Genel olarak, aşağıdaki modül:

defmodule Example do
  use Feature, option: :value
end

derlendi

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

14

Python / Java / Golang dillerinden gelen geçmişle, importvs usede benim için karıştırıldı. Bu, kodun yeniden kullanım mekanizmasını bazı bildirimsel dil örnekleriyle açıklayacaktır.

ithalat

Kısacası Elixir'de modülleri içe aktarmanıza gerek yok. Tüm genel işlevlere tam nitelikli MODULE.FUNCTION sözdizimi ile erişilebilir:

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

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

Python / Java / Golang'da, bu MODÜL'deki import MODULEişlevleri kullanmadan önce yapmanız gerekir , örneğin Python

In []: import math

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

O zaman importElixir'in yaptığı şey sizi şaşırtabilir:

Tam nitelikli adı kullanmadan diğer modüllerden işlevlere veya makrolara kolayca erişmek istediğimizde içe aktarmayı kullanırız.

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

Yani yazmak istiyorsanız sqrtyerine Integer.sqrt, trimyerine String.trim, importirade yardım

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

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

Bu, kod okumada sorunlara neden olabilir ve isim çatışması olduğunda Erlang'da (Elixir'i etkileyen dil) önerilmez . Ancak Elixir'de böyle bir kural yoktur, kendi sorumluluğunuzdadır kullanabilirsiniz.

Python'da aynı etki şu şekilde yapılabilir:

from math import * 

ve sadece bazı özel senaryolarda / etkileşimli modda kullanılması önerilir - daha kısa / hızlı yazma için.

kullan ve gerektir

Yapan use/ requirefarklı kılan şey, "makro" ile - Python / Java / Golang ... ailesinde bulunmayan kavramla - ilişkili olmalarıdır.

Sen gerekmez importfonksiyonları kullanmak için bir modül, ancak gerek requirekendi makroları kullanmak için bir modül :

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

Gerçi is_evennormal bir fonksiyonu olarak yazılabilir, bu bir makro çünkü:

Elixir'de, Tamsayı.is_odd / 1, koruma olarak kullanılabilmesi için bir makro olarak tanımlanır.

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

useElixir belgesinden alıntı yapmak için:

kullanımı, verilen modülü gerektirir ve daha sonra __using__/1modülün mevcut içeriğe bazı kodları enjekte etmesine izin veren geri aramayı çağırır .

defmodule Example do
  use Feature, option: :value
end

derlendi

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

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

Yani yazmak yazmakla use Xaynı

require X
X.__using__()

use/2 bir makrodur , makro kodu sizin için başka bir koda dönüştürecektir.

Ne use MODULEzaman isteyeceksin:

  • makrolarına erişmek istiyorum ( require)
  • VE yürüt MODULE.__using__()

Elixir 1.5'te test edildi


3

use Module gerektirir Module ve ayrıca çağırır __using__.

import ModuleModuleişlevselliği güncel bağlama getirir , sadece gerektirmez.


0

İthalat

Belirli bir modüldeki tüm işlevleri ve makroları çağrıldığı sözcük kapsamının içinde erişilebilir hale getirir. Çoğu durumda, içe aktarılmak için yalnızca bir veya daha fazla işleve / makroya ihtiyacınız olduğunu unutmayın.

Misal:

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

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

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

kullanım

Bu makro , geçerli modüldeki herhangi bir kodu enjekte etmenize izin verir . Dış kitaplıkları kullanırken dikkatli olmalısınız use, çünkü perde arkasında tam olarak ne olduğundan emin olamayabilirsiniz.

Misal:

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

Modül içerisine sahne arkası kodu __using__enjekte edilmiştir TextPrinter.

Bu arada, Elixir'de daha fazla bağımlılık yönetimi talimatı var .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.