Elixir 1.7

Kernel.SpecialForms




elixir

Kernel.SpecialForms

विशेष रूप एलिक्सिर के मूल बिल्डिंग ब्लॉक हैं, और इसलिए डेवलपर द्वारा ओवरराइड नहीं किया जा सकता है।

हम उन्हें इस मॉड्यूल में परिभाषित करते हैं। इनमें से कुछ रूप लेक्सिकल हैं (जैसे alias/2 , case/2 , आदि)। मैक्रोज़ {}/1 और <<>>/1 भी विशेष रूप हैं जिनका उपयोग क्रमशः टपल और बाइनरी डेटा संरचनाओं को परिभाषित करने के लिए किया जाता है।

यह मॉड्यूल मैक्रोज़ का भी दस्तावेज है जो __ENV__/0 के संकलन पर्यावरण के बारे में जानकारी लौटाता है, जैसे ( __ENV__/0 , __MODULE__/0 , __DIR__/0 और __CALLER__/0 )।

अंत में, यह दो विशेष रूपों, __block__/1 और __aliases__/1 भी दस्तावेज़ित करता है, जिन्हें सीधे डेवलपर द्वारा बुलाया जाना नहीं है, लेकिन वे उद्धृत सामग्री में दिखाई देते हैं क्योंकि वे अमृत के निर्माण में आवश्यक हैं।

सारांश

कार्य

%struct{}

मेल खाता है या एक संरचना बनाता है

%{}

एक नक्शा बनाता है

&(expr)

एक अनाम फ़ंक्शन कैप्चर करता है या बनाता है

बाएं । सही

एक दूरस्थ कॉल, एक अनाम फ़ंक्शन या एक उपनाम के लिए कॉल परिभाषित करता है

बाएँ दांए

प्रकार और बिटस्ट्रिंग्स द्वारा उपयोग किए जाने वाले प्रकार निर्दिष्ट करने के लिए

<<args>>

एक नई बिटस्ट्रिंग को परिभाषित करता है

बाएँ = दाएँ

मूल्य को बाईं ओर पैटर्न के खिलाफ दाईं ओर मेल खाता है

^var

मैच क्लॉस में पहले से मौजूद चर को एक्सेस करता है। पिन ऑपरेटर के रूप में भी जाना जाता है

__CALLER__/0

वर्तमान कॉलिंग वातावरण को Macro.Env संरचना के रूप में Macro.Env

__DIR__/0

बाइनरी के रूप में वर्तमान फ़ाइल की निर्देशिका का निरपेक्ष पथ लौटाता है

__ENV__/0

Macro.Env संरचना के रूप में वर्तमान परिवेश की जानकारी देता है

__MODULE__/0

वर्तमान मॉड्यूल का नाम एक परमाणु या nil अन्यथा

__STACKTRACE__

घुंघराले संभाले अपवाद के लिए स्टैकट्रेस लौटाता है

__aliases__/1

उपनामों की जानकारी रखने के लिए आंतरिक विशेष रूप

__block__/1

ब्लॉक अभिव्यक्तियों के लिए आंतरिक विशेष रूप

alias/2

alias/2 का उपयोग उपनाम सेट करने के लिए किया जाता है, अक्सर मॉड्यूल नामों के साथ उपयोगी होता है

case/2

दिए गए क्लॉज़ के विरुद्ध दी गई अभिव्यक्ति से मेल खाता है

cond(clauses)

पहले खंड के अनुरूप अभिव्यक्ति का मूल्यांकन करता है जो एक सत्य मूल्य का मूल्यांकन करता है

fn [खंड] अंत

एक अनाम फ़ंक्शन को परिभाषित करता है

for(args)

समझदारी आपको एक एन्यूमरबल या बिटस्ट्रिंग से डेटा संरचना को जल्दी से बनाने की अनुमति देती है

आयात (मॉड्यूल, ऑप्स)

अन्य मॉड्यूल से आयात कार्य और मैक्रोज़

बोली (opts, ब्लॉक)

किसी भी अभिव्यक्ति का प्रतिनिधित्व करता है

receive(args)

जाँचता है कि क्या वर्तमान प्रक्रिया मेलबॉक्स में दिए गए खंडों से मेल खाता कोई संदेश है

आवश्यकता (मॉड्यूल, ऑप्स)

इसके मैक्रोज़ का उपयोग करने के लिए एक मॉड्यूल की आवश्यकता होती है

super(args)

जब यह Kernel.defoverridable/1 साथ ओवरराइड करता है तो ओवरराइड फ़ंक्शन को कॉल करता है

try(args)

दिए गए भावों का मूल्यांकन करता है और किसी भी त्रुटि, निकास, या फेंकने वाले को संभालता है

unquote(expr)

किसी मैक्रो के अंदर से दी गई अभिव्यक्ति को रेखांकित करता है

unquote_splicing(expr)

दी गई सूची को अपने तर्कों का विस्तार करते हुए रेखांकित करता है। unquote(expr) समान

with(args)

मैचिंग क्लॉज को मिलाते थे

{args}

टपल बनाता है

कार्य

% संरचना {} (मैक्रो)

मेल खाता है या एक संरचना बनाता है।

एक ढांचा एक टैग किया हुआ नक्शा है जो डेवलपर्स को कुंजी के लिए डिफ़ॉल्ट मान प्रदान करने की अनुमति देता है, टैग बहुरूपीय प्रेषण में उपयोग किए जाने वाले और समय के दावे को संकलित करने के लिए।

Kernel.defstruct/1 आमतौर पर Kernel.defstruct/1 साथ परिभाषित की Kernel.defstruct/1 Kernel.defstruct/1 मैक्रो:

defmodule User do
  defstruct name: "john", age: 27
end

अब एक संरचना इस प्रकार बनाई जा सकती है:

%User{}

एक संरचना के नीचे सिर्फ एक नक्शा है :__struct__ User मॉड्यूल की ओर इशारा करते हुए :__struct__ कुंजी

%User{} == %{__struct__: User, name: "john", age: 27}

संरचना बनाते समय संरचना क्षेत्र दिए जा सकते हैं:

%User{age: 31}
#=> %{__struct__: User, name: "john", age: 31}

या मूल्यों को बाहर निकालने के लिए मिलान के पैटर्न पर भी:

%User{age: age} = user

संरचना के लिए विशिष्ट अपडेट ऑपरेशन भी उपलब्ध है:

%User{user | age: 28}

संरचना का लाभ यह है कि वे इस बात को मान्य करते हैं कि दी गई चाबियां परिभाषित संरचना का हिस्सा हैं। नीचे दिया गया उदाहरण विफल हो जाएगा क्योंकि कोई कुंजी नहीं है :full_name User संरचना में :full_name :

%User{full_name: "john doe"}

ऊपर दिए गए सिंटैक्स की गारंटी होगी कि दिए गए कुंजियाँ संकलन समय पर मान्य हैं और यह रनटाइम पर गारंटी देगा कि दी गई तर्क एक संरचना है, अन्यथा BadStructError साथ विफल।

हालांकि संरचनाएं नक्शे हैं, डिफ़ॉल्ट रूप से संरचनाएं नक्शे के लिए लागू किसी भी प्रोटोकॉल को लागू नहीं करती हैं। पॉलीमोर्फिक डिस्पैच के लिए प्रोटोकॉल के साथ कैसे उपयोग किया जा सकता है, इसके बारे में अधिक जानकारी के लिए Kernel.defprotocol/2 जांच करें। साथ ही, Kernel.struct/2 बनाने और अपडेट करने के तरीके के बारे में उदाहरण के लिए Kernel.struct/2 और Kernel.struct!/2

पैटर्न नाम पर पैटर्न मिलान

संरचनात्मक क्षेत्रों पर पैटर्न मिलान की अनुमति के अलावा, जैसे:

%User{age: age} = user

संरचनाएं संरचना नाम पर मिलान करने की भी अनुमति देती हैं:

%struct_name{} = user
struct_name #=> User

जब आप यह जाँचना चाहें कि क्या कोई संरचना है, लेकिन आप इसके नाम में कोई दिलचस्पी नहीं रखते हैं, तो आप उस संरचनात्मक नाम को भी असाइन कर सकते हैं:

%_{} = user

% {} (मैक्रो)

एक नक्शा बनाता है।

Map , उनके सिंटैक्स और उनके उपयोग और हेरफेर करने के तरीकों के बारे में अधिक जानकारी के लिए Map मॉड्यूल देखें।

एएसटी प्रतिनिधित्व

भले ही => या कीवर्ड सिंटैक्स का उपयोग किया गया हो, मानचित्र में कुंजी-मूल्य वाले जोड़े हमेशा सादगी के लिए दो-तत्व ट्यूपल्स की सूची के रूप में आंतरिक रूप से दर्शाए जाते हैं:

iex> quote do
...>   %{"a" => :b, c: :d}
...> end
{:%{}, [], [{"a", :b}, {:c, :d}]}

और (एक्सप) (मैक्रो)

एक अनाम फ़ंक्शन कैप्चर करता है या बनाता है।

कब्जा

कैप्चर ऑपरेटर का उपयोग आमतौर पर किसी मॉड्यूल से दिए गए नाम और समानता के साथ एक फ़ंक्शन को पकड़ने के लिए किया जाता है:

iex> fun = &Kernel.is_atom/1
iex> fun.(:atom)
true
iex> fun.("string")
false

ऊपर के उदाहरण में, हमने Kernel.is_atom/1 को एक अनाम फ़ंक्शन के रूप में कैप्चर किया और फिर इसे लागू किया।

कैप्चर ऑपरेटर का उपयोग निजी कार्यों सहित स्थानीय कार्यों को पकड़ने के लिए भी किया जा सकता है, और मॉड्यूल नाम को छोड़ कर आयातित कार्यों को:

&local_function/1

अनाम कार्य

कैप्चर ऑपरेटर का उपयोग आंशिक रूप से कार्यों को लागू करने के लिए भी किया जा सकता है, जहां &1 , &2 और इतने पर मूल्य प्लेसहोल्डर्स के रूप में उपयोग किया जा सकता है। उदाहरण के लिए:

iex> double = &(&1 * 2)
iex> double.(2)
4

दूसरे शब्दों में, &(&1 * 2) fn x -> x * 2 end बराबर है।

हम आंशिक रूप से प्लेसहोल्डर के साथ एक दूरस्थ फ़ंक्शन लागू कर सकते हैं:

iex> take_five = &Enum.take(&1, 5)
iex> take_five.(1..10)
[1, 2, 3, 4, 5]

एक अन्य उदाहरण एक आयातित या स्थानीय फ़ंक्शन का उपयोग करते समय:

iex> first_elem = &elem(&1, 0)
iex> first_elem.({0, 1})
0

ऑपरेटर को अधिक जटिल अभिव्यक्तियों के साथ प्रयोग किया जा सकता है:

iex> fun = &(&1 + &2 + &3)
iex> fun.(1, 2, 3)
6

साथ ही सूचियों और टुपल्स के साथ:

iex> fun = &{&1, &2}
iex> fun.(1, 2)
{1, 2}

iex> fun = &[&1 | &2]
iex> fun.(1, [2, 3])
[1, 2, 3]

अनाम फ़ंक्शंस बनाते समय एकमात्र प्रतिबंध यह है कि कम से कम एक प्लेसहोल्डर मौजूद होना चाहिए, अर्थात इसमें कम से कम &1 होना चाहिए, और यह कि ब्लॉक एक्सप्रेशन समर्थित नहीं हैं:

# No placeholder, fails to compile.
&(:foo)

# Block expression, fails to compile.
&(&1; &2)

बाएं । सही (मैक्रो)

एक दूरस्थ कॉल, एक अनाम फ़ंक्शन या एक उपनाम के लिए कॉल परिभाषित करता है।

एलिक्सिर में डॉट ( . ) का उपयोग दूरस्थ कॉल के लिए किया जा सकता है:

iex> String.downcase("FOO")
"foo"

ऊपर के इस उदाहरण में, हमने उपयोग किया है . String मॉड्यूल में नीचे आने के लिए, "FOO" को तर्क के रूप में पारित करें।

अनाम कार्यों को लागू करने के लिए बिंदी का उपयोग किया जा सकता है:

iex> (fn n -> n end).(7)
7

जिस स्थिति में बायीं ओर एक फंक्शन है।

हम उपनाम बनाने के लिए डॉट का भी उपयोग कर सकते हैं:

iex> Hello.World
Hello.World

इस बार, हम दो उपनामों में शामिल हो गए हैं, अंतिम उर्फ Hello.World को परिभाषित करते Hello.World

वाक्य - विन्यास

के दाईं ओर . हो सकता है कि यह एक ऐसा शब्द है, जो ऊपर की ओर से शुरू होता है, जो एक उपनाम, एक शब्द है जो लोअरकेस या अंडरस्कोर, किसी भी मान्य भाषा ऑपरेटर या सिंगल-डबल-कोट्स में लिपटे किसी भी नाम से शुरू होता है। वे सभी मान्य उदाहरण हैं:

iex> Kernel.Sample
Kernel.Sample

iex> Kernel.length([1, 2, 3])
3

iex> Kernel.+(1, 2)
3

iex> Kernel."+"(1, 2)
3

ध्यान दें कि फ़ंक्शन नाम को सिंगल या डबल-कोट्स में लपेटना हमेशा एक दूरस्थ कॉल है। इसलिए Kernel."Foo" फ़ंक्शन को "फू" कहने का प्रयास करेगा और उर्फ Kernel.Foo वापस नहीं Kernel.Foo । यह डिज़ाइन द्वारा किया जाता है क्योंकि फ़ंक्शन नामों की तुलना में मॉड्यूल नाम अधिक सख्त होते हैं।

जब एक गुमनाम फ़ंक्शन को लागू करने के लिए डॉट का उपयोग किया जाता है, तो केवल एक ऑपरेंड होता है, लेकिन यह अभी भी एक पोस्टफिक्स नोटेशन का उपयोग करके लिखा जाता है:

iex> negate = fn n -> -n end
iex> negate.(7)
-7

उद्धृत अभिव्यक्ति

कब . उपयोग किया जाता है, उद्धृत अभिव्यक्ति दो अलग-अलग रूप ले सकती है। जब दाईं ओर एक लोअरकेस अक्षर (या अंडरस्कोर) के साथ शुरू होता है:

iex> quote do
...>   String.downcase("FOO")
...> end
{{:., [], [{:__aliases__, [alias: false], [:String]}, :downcase]}, [], ["FOO"]}

ध्यान दें कि हमारे पास एक आंतरिक गुच्छ है, जिसमें परमाणु है :. पहले तत्व के रूप में डॉट का प्रतिनिधित्व:

{:., [], [{:__aliases__, [alias: false], [:String]}, :downcase]}

यह ट्यूपल एलिक्जिर में सामान्य उद्धृत अभिव्यक्ति संरचना का अनुसरण करता है, पहले तर्क के रूप में नाम, दूसरे के रूप में मेटाडेटा के रूप में कुछ कीवर्ड सूची और तीसरे के रूप में तर्कों की सूची। इस मामले में, तर्क उर्फ String और परमाणु हैं :downcase । रिमोट कॉल में दूसरा तर्क हमेशा एक परमाणु होता है।

अनाम फ़ंक्शंस के लिए कॉल के मामले में, डॉट स्पेशल फॉर्म के साथ इनर टपल का केवल एक तर्क है, इस तथ्य को दर्शाता है कि ऑपरेटर एकात्मक है:

iex> quote do
...>   negate.(0)
...> end
{{:., [], [{:negate, [], __MODULE__}]}, [], [0]}

जब दाईं ओर एक उपनाम (यानी अपरकेस से शुरू होता है), हम इसके बजाय प्राप्त करते हैं:

iex> quote do
...>   Hello.World
...> end
{:__aliases__, [alias: false], [:Hello, :World]}

हम __aliases__/1 विशेष फॉर्म प्रलेखन में उपनामों के बारे में अधिक जानकारी में जाते हैं।

Unquoting

हम एक उद्धृत अभिव्यक्ति में रिमोट कॉल उत्पन्न करने के लिए अयोग्य का भी उपयोग कर सकते हैं:

iex> x = :downcase
iex> quote do
...>   String.unquote(x)("FOO")
...> end
{{:., [], [{:__aliases__, [alias: false], [:String]}, :downcase]}, [], ["FOO"]}

Kernel."FUNCTION_NAME" समान Kernel."FUNCTION_NAME" , unquote(x) हमेशा x के मान से स्वतंत्र एक दूरस्थ कॉल उत्पन्न करेगा। उद्धृत अभिव्यक्ति के माध्यम से एक उपनाम उत्पन्न करने के लिए, किसी को Module.concat/2 पर भरोसा करने की आवश्यकता है:

iex> x = Sample
iex> quote do
...>   Module.concat(String, unquote(x))
...> end
{{:., [], [{:__aliases__, [alias: false], [:Module]}, :concat]}, [],
 [{:__aliases__, [alias: false], [:String]}, Sample]}

बाएँ :: दाएँ (मैक्रो)

प्रकार और बिटस्ट्रिंग्स द्वारा उपयोग किए जाने वाले प्रकार निर्दिष्ट करने के लिए।

इस ऑपरेटर का उपयोग अमृत में दो अलग-अलग अवसरों में किया जाता है। इसका उपयोग चर में, चर या प्रकार के प्रकार को निर्दिष्ट करने के लिए किया जाता है:

@type number :: integer | float
@spec add(number, number) :: number

किसी दिए गए बिट खंड के प्रकार को निर्दिष्ट करने के लिए इसका उपयोग बिट स्ट्रिंग्स में भी किया जा सकता है:

<<int::integer-little, rest::bits>> = bits

टाइपस्पेस और बिटस्ट्रिंग्स के बारे में अधिक जानकारी के लिए क्रमशः Typespec पेज और <<>>/1 पर प्रलेखन पढ़ें।

<< args >> (मैक्रो)

एक नई बिटस्ट्रिंग को परिभाषित करता है।

उदाहरण

iex> <<1, 2, 3>>
<<1, 2, 3>>

प्रकार

एक बिटस्ट्रिंग कई खंडों से बना है और प्रत्येक खंड में एक प्रकार है। बिटस्ट्रिंग्स में 9 प्रकारों का उपयोग किया जाता है:

  • integer
  • float
  • bits ( bitstring लिए उपनाम)
  • bitstring
  • binary
  • bytes ( binary लिए उपनाम)
  • utf8
  • utf16
  • utf32

जब कोई प्रकार निर्दिष्ट नहीं किया जाता है, तो डिफ़ॉल्ट integer :

iex> <<1, 2, 3>>
<<1, 2, 3>>

अमृत ​​भी डिफ़ॉल्ट रूप से सेगमेंट को शाब्दिक स्ट्रिंग या शाब्दिक चार्टलिस्ट के रूप में स्वीकार करता है, जो डिफ़ॉल्ट रूप से पूर्णांक तक विस्तारित हैं:

iex> <<0, "foo">>
<<0, 102, 111, 111>>

चर या किसी अन्य प्रकार को स्पष्ट रूप से टैग किए जाने की आवश्यकता है:

iex> rest = "oo"
iex> <<102, rest>>
** (ArgumentError) argument error

हम इसे binary रूप में स्पष्ट रूप से टैग करके हल कर सकते हैं:

iex> rest = "oo"
iex> <<102, rest::binary>>
"foo"

utf16 , utf16 और utf32 प्रकार यूनिकोड utf32 लिए हैं। उन्हें शाब्दिक तार और चार्लिस्ट पर भी लागू किया जा सकता है:

iex> <<"foo"::utf16>>
<<0, 102, 0, 111, 0, 111>>
iex> <<"foo"::utf32>>
<<0, 0, 0, 102, 0, 0, 0, 111, 0, 0, 0, 111>>

विकल्प

विभाजक के रूप में - का उपयोग करके कई विकल्प दिए जा सकते हैं। आदेश मनमाना है, इसलिए निम्नलिखित सभी समान हैं:

<<102::integer-native, rest::binary>>
<<102::native-integer, rest::binary>>
<<102::unsigned-big-integer, rest::binary>>
<<102::unsigned-big-integer-size(8), rest::binary>>
<<102::unsigned-big-integer-8, rest::binary>>
<<102::8-integer-big-unsigned, rest::binary>>
<<102, rest::binary>>

इकाई और आकार

मैच की लंबाई unit बराबर होती है (बिट्स की एक संख्या) size (लंबाई unit के दोहराया खंडों की संख्या) के बराबर होती है।

प्रकार डिफ़ॉल्ट इकाई
integer 1 बिट
float 1 बिट
binary 8 बिट्स

प्रकारों के लिए आकार कुछ अधिक बारीक होते हैं। पूर्णांकों के लिए डिफ़ॉल्ट आकार 8 है।

फ़्लोट्स के लिए, यह 64 है। फ़्लोट्स के लिए, size * unit का परिणाम क्रमशः IEEE 754 बाइनरी 32 और बाइनरी 64 के अनुरूप 32 या 64 में होना चाहिए।

बायनेरिज़ के लिए, डिफ़ॉल्ट बाइनरी का आकार है। केवल एक मैच में अंतिम बाइनरी डिफ़ॉल्ट आकार का उपयोग कर सकता है। अन्य सभी को अपना आकार स्पष्ट रूप से निर्दिष्ट करना चाहिए, भले ही मैच अस्पष्ट हो। उदाहरण के लिए:

iex> <<name::binary-size(5), " the ", species::binary>> = <<"Frank the Walrus">>
"Frank the Walrus"
iex> {name, species}
{"Frank", "Walrus"}

असफल होने के लिए गैर-अंतिम कारणों के लिए आकार निर्दिष्ट करने में विफल:

<<name::binary, " the ", species::binary>> = <<"Frank the Walrus">>
** (CompileError): a binary field without size is only allowed at the end of a binary pattern

शॉर्टकट सिंटैक्स

पूर्णांक मानों को पास करते समय आकार और इकाई को एक सिंटैक्स शॉर्टकट का उपयोग करके भी निर्दिष्ट किया जा सकता है:

iex> x = 1
iex> <<x::8>> == <<x::size(8)>>
true
iex> <<x::8*4>> == <<x::size(8)-unit(4)>>
true

यह सिंटैक्स इस तथ्य को दर्शाता है कि यूनिट द्वारा आकार को गुणा करके प्रभावी आकार दिया जाता है।

संशोधक

कुछ प्रकारों में बाइट प्रतिनिधित्व में अस्पष्टता को साफ करने के लिए संशोधक जुड़े होते हैं।

संशोधक प्रासंगिक प्रकार
signed integer
unsigned (डिफ़ॉल्ट) integer
little integer , float , utf16 , utf32
big (डिफ़ॉल्ट) integer , float , utf16 , utf32
native integer , utf16 , utf32

संकेत

घुसपैठियों को signed या unsigned किया जा सकता है, unsigned करने के लिए डिफ़ॉल्ट।

iex> <<int::integer>> = <<-100>>
<<156>>
iex> int
156
iex> <<int::integer-signed>> = <<-100>>
<<156>>
iex> int
-100

signed और unsigned केवल बायनेरिज़ (नीचे देखें) के लिए उपयोग किए जाते हैं और केवल पूर्णांकों के लिए उपयोग किए जाते हैं।

iex> <<-100::signed, _rest::binary>> = <<-100, "foo">>
<<156, 102, 111, 111>>

endianness

अमृत ​​के पास धीरज रखने के तीन विकल्प हैं: big , little और native । डिफ़ॉल्ट big :

iex> <<number::little-integer-size(16)>> = <<0, 1>>
<<0, 1>>
iex> number
256
iex> <<number::big-integer-size(16)>> = <<0, 1>>
<<0, 1>>
iex> number
1

वीएम स्टार्टअप पर वीएम द्वारा निर्धारित किया जाता है और मेजबान ऑपरेटिंग सिस्टम पर निर्भर करेगा।

बाइनरी / बिटस्ट्रिंग मिलान

द्विआधारी मिलान एलिक्सिर में एक शक्तिशाली विशेषता है जो बायनेरिज़ के साथ-साथ पैटर्न मिलान से जानकारी निकालने के लिए उपयोगी है।

बायनेरी मिलान का उपयोग स्वयं बायनेरिज़ से जानकारी निकालने के लिए किया जा सकता है:

iex> <<"Hello, ", place::binary>> = "Hello, World"
"Hello, World"
iex> place
"World"

या पैटर्न मैच के लिए फ़ंक्शन परिभाषाओं के एक भाग के रूप में:

defmodule ImageTyper do
  @png_signature <<137::size(8), 80::size(8), 78::size(8), 71::size(8),
                   13::size(8), 10::size(8), 26::size(8), 10::size(8)>>
  @jpg_signature <<255::size(8), 216::size(8)>>

  def type(<<@png_signature, rest::binary>>), do: :png
  def type(<<@jpg_signature, rest::binary>>), do: :jpg
  def type(_), do :unknown
end

प्रदर्शन और अनुकूलन

Erlang संकलक बाइनरी निर्माण और मिलान पर कई अनुकूलन प्रदान कर सकता है। ऑप्टिमाइज़ेशन आउटपुट देखने के लिए, bin_opt_info कंपाइलर विकल्प सेट करें:

ERL_COMPILER_OPTIONS=bin_opt_info mix compile

विशिष्ट अनुकूलन और प्रदर्शन के विचारों के बारे में अधिक जानने के लिए, बायलर को संभालने पर एरलंग की दक्षता गाइड देखें

बाएँ = दाएँ (स्थूल)

मूल्य को बाईं ओर पैटर्न के खिलाफ दाईं ओर मेल खाता है।

^ वर (मैक्रो)

मैच क्लॉस में पहले से मौजूद चर को एक्सेस करता है। पिन ऑपरेटर के रूप में भी जाना जाता है।

उदाहरण

अमृत ​​स्थिर एकल असाइनमेंट के माध्यम से चर को पुनर्जन्म करने की अनुमति देता है:

iex> x = 1
iex> x = x + 1
iex> x
2

हालांकि, कुछ स्थितियों में, रिबॉन्डिंग के बजाय मौजूदा मूल्य के खिलाफ मैच करना उपयोगी है। यह ^ विशेष रूप के साथ किया जा सकता है, आम तौर पर पिन ऑपरेटर के रूप में जाना जाता है:

iex> x = 1
iex> ^x = List.first([1])
iex> ^x = List.first([2])
** (MatchError) no match of right hand side value: 2

ध्यान दें कि ^x हमेशा मैच से पहले x के मान को संदर्भित करता है। निम्न उदाहरण मेल खाएगा:

iex> x = 0
iex> {x, ^x} = {1, 0}
iex> x
1

__CALLER__ (मैक्रो)

वर्तमान कॉलिंग वातावरण को Macro.Env संरचना के रूप में Macro.Env

वातावरण में आप फ़ाइल नाम, लाइन नंबर, सेट अप अलायस, फंक्शन और अन्य का उपयोग कर सकते हैं।

__DIR__ (मैक्रो)

बाइनरी के रूप में वर्तमान फ़ाइल की निर्देशिका का निरपेक्ष पथ लौटाता है।

हालांकि निर्देशिका को Path.dirname(__ENV__.file) रूप में एक्सेस किया जा सकता है, लेकिन यह मैक्रो एक सुविधाजनक शॉर्टकट है।

__ENV__ (मैक्रो)

Macro.Env . Macro.Env संरचना के रूप में वर्तमान परिवेश की जानकारी देता है।

वातावरण में आप वर्तमान फ़ाइल नाम, लाइन नंबर, उपनाम सेट कर सकते हैं, वर्तमान फ़ंक्शन और अन्य।

__MODULE__ (मैक्रो)

वर्तमान मॉड्यूल का नाम एक परमाणु या nil अन्यथा।

यद्यपि मॉड्यूल को __ENV__/0 में एक्सेस किया जा सकता है, लेकिन यह मैक्रो एक सुविधाजनक शॉर्टकट है।

__STACKTRACE__ (मैक्रो)

घुंघराले संभाले अपवाद के लिए स्टैकट्रेस लौटाता है।

यह केवल try(args) भाव के catch और rescue खंड में उपलब्ध है।

__aliases __ (आर्ग्स) (मैक्रो)

उपनामों की जानकारी रखने के लिए आंतरिक विशेष रूप।

यह आमतौर पर एक परमाणु के लिए संकलित किया जाता है:

iex> quote do
...>   Foo.Bar
...> end
{:__aliases__, [alias: false], [:Foo, :Bar]}

अमृत Foo.Bar रूप में __aliases__ प्रतिनिधित्व करता है, इसलिए कॉल को ऑपरेटर द्वारा स्पष्ट रूप से पहचाना जा सकता है :. । उदाहरण के लिए:

iex> quote do
...>   Foo.bar
...> end
{{:., [], [{:__aliases__, [alias: false], [:Foo]}, :bar]}, [], []}

जब भी एक अभिव्यक्ति पुनरावृत्ति को देखता है a :. टपल कुंजी के रूप में, यह सुनिश्चित किया जा सकता है कि यह एक कॉल का प्रतिनिधित्व करता है और सूची में दूसरा तर्क एक परमाणु है।

दूसरी ओर, उपनाम कुछ गुण रखते हैं:

  1. उपनामों का मुख्य तत्व कोई भी शब्द हो सकता है जिसे संकलन समय पर एक परमाणु तक विस्तारित होना चाहिए।

  2. एलियंस के पूंछ तत्वों को हमेशा परमाणु होने की गारंटी दी जाती है।

  3. जब उपनामों का मुख्य तत्व परमाणु होता है :Elixir , कोई विस्तार नहीं होता है।

__ब्लॉक __ (आर्ग्स) (मैक्रो)

ब्लॉक अभिव्यक्तियों के लिए आंतरिक विशेष रूप।

जब भी हम अमृत में अभिव्यक्तियों का खंड होते हैं तो यह विशेष रूप होता है। यह विशेष रूप निजी है और इसे सीधे लागू नहीं किया जाना चाहिए:

iex> quote do
...>   1
...>   2
...>   3
...> end
{:__block__, [], [1, 2, 3]}

उपनाम (मॉड्यूल, ऑप्स) (मैक्रो)

alias/2 का उपयोग उपनाम सेट करने के लिए किया जाता है, अक्सर मॉड्यूल नामों के साथ उपयोगी होता है।

उदाहरण

alias/2 का उपयोग किसी भी मॉड्यूल के लिए एक उपनाम स्थापित करने के लिए किया जा सकता है:

defmodule Math do
  alias MyKeyword, as: Keyword
end

ऊपर के उदाहरण में, हमने Keyword रूप में MyKeyword लिए MyKeyword स्थापना की है। तो अब, Keyword किसी भी संदर्भ को स्वचालित रूप से MyKeyword द्वारा प्रतिस्थापित किया MyKeyword

यदि कोई मूल Keyword एक्सेस करना चाहता है, तो वह Elixir किया जा सकता है:

Keyword.values   #=> uses MyKeyword.values
Elixir.Keyword.values #=> uses Keyword.values

ध्यान दें कि बिना कॉल किए हुए alias as: विकल्प स्वचालित रूप से मॉड्यूल के अंतिम भाग के आधार पर एक उपनाम सेट करता है। उदाहरण के लिए:

alias Foo.Bar.Baz

के समान है:

alias Foo.Bar.Baz, as: Baz

हम भी एक लाइन में कई मॉड्यूल उर्फ:

alias Foo.{Bar, Baz, Biz}

के समान है:

alias Foo.Bar
alias Foo.Baz
alias Foo.Biz

लेक्सिकल स्कोप

import/2 , require/2 और alias/2 को निर्देश कहा जाता है और सभी में शाब्दिक गुंजाइश होती है। इसका मतलब है कि आप विशिष्ट कार्यों के अंदर उपनाम सेट कर सकते हैं और यह समग्र दायरे को प्रभावित नहीं करेगा।

चेतावनी

यदि आप एक मॉड्यूल को उर्फ ​​करते हैं और आप उपनाम का उपयोग नहीं करते हैं, तो एलिक्सिर एक चेतावनी जारी करने जा रहा है जिसका अर्थ है कि उपनाम का उपयोग नहीं किया जा रहा है।

यदि उपनाम किसी मैक्रो द्वारा स्वचालित रूप से उत्पन्न होता है, तो एलिक्सिर किसी भी चेतावनी का उत्सर्जन नहीं करेगा, क्योंकि उपनाम स्पष्ट रूप से परिभाषित नहीं किया गया था।

दोनों चेतावनी व्यवहारों को स्पष्ट रूप से सेट करके बदला जा सकता है :warn true या false लिए :warn विकल्प।

स्थिति (स्थिति, खंड) (स्थूल)

दिए गए क्लॉज़ के विरुद्ध दी गई अभिव्यक्ति से मेल खाता है।

उदाहरण

case thing do
  {:selector, i, value} when is_integer(i) ->
    value
  value ->
    value
end

ऊपर दिए गए उदाहरण में, हम प्रत्येक क्लॉज "हेड" के खिलाफ मैच करते हैं और उस क्लॉज "बॉडी" पर अमल करते हैं जो कि मैच के पहले क्लॉज के अनुरूप है।

यदि कोई क्लॉज मेल नहीं खाता है, तो एक त्रुटि उठाई जाती है। इस कारण से, अंतिम कैच-ऑल क्लॉज (जैसे _ ) जोड़ना आवश्यक हो सकता है जो हमेशा मेल खाता रहेगा।

x = 10

case x do
  0 ->
    "This clause won't match"
  _ ->
    "This clause would match any value (x = #{x})"
end
#=> "This clause would match any value (x = 10)"

चर संभालना

ध्यान दें कि एक खंड "सिर" में बंधे चर बाहरी संदर्भ में लीक नहीं होते हैं:

case data do
  {:ok, value} -> value
  :error -> nil
end

value #=> unbound variable value

हालाँकि, क्लॉज "बॉडी" में स्पष्ट रूप से बंधे हुए चर बाहरी संदर्भ से सुलभ हैं:

value = 7

case lucky? do
  false -> value = 13
  true  -> true
end

value #=> 7 or 13

उपरोक्त उदाहरण में, lucky? के मूल्य के आधार पर मूल्य 7 या 13 होने वाला है lucky? । यदि केस से पहले केस value का कोई पिछला मूल्य नहीं है, तो ऐसे क्लॉज़ जो किसी वैल्यू को स्पष्ट रूप से बाँधते नहीं हैं, उनके पास nil बंधा हुआ वैरिएबल है।

यदि आप किसी मौजूदा वैरिएबल के मुकाबले मैच करना चाहते हैं, तो आपको ^/1 ऑपरेटर का उपयोग करना होगा:

x = 1

case 10 do
  ^x -> "Won't match"
  _  -> "Will match"
end
#=> "Will match"

कंडोम (खंड) (स्थूल)

पहले खंड के अनुरूप अभिव्यक्ति का मूल्यांकन करता है जो एक सत्य मूल्य का मूल्यांकन करता है।

cond do
  hd([1, 2, 3]) ->
    "1 is considered as true"
end
#=> "1 is considered as true"

यदि सभी स्थितियाँ nil या false मूल्यांकन करती हैं, तो एक त्रुटि उत्पन्न होती है। इस कारण से, हमेशा एक अंतिम हमेशा-सत्य स्थिति (कुछ भी गैर- false और गैर- nil ) को जोड़ना आवश्यक हो सकता है, जो हमेशा मेल खाता होगा।

उदाहरण

cond do
  1 + 1 == 1 ->
    "This will never match"
  2 * 2 != 4 ->
    "Nor this"
  true ->
    "This will"
end
#=> "This will"

fn [खंड] अंत (स्थूल)

एक अनाम फ़ंक्शन को परिभाषित करता है।

उदाहरण

iex> add = fn a, b -> a + b end
iex> add.(1, 2)
3

बेनामी कार्यों में कई खंड भी हो सकते हैं। सभी खंडों को समान तर्क की अपेक्षा करनी चाहिए:

iex> negate = fn
...>   true -> false
...>   false -> true
...> end
iex> negate.(false)
true

के लिए (args) (मैक्रो)

समझदारी आपको एक एन्यूमरबल या बिटस्ट्रिंग से डेटा संरचना को जल्दी से बनाने की अनुमति देती है।

एक उदाहरण से शुरू करते हैं:

iex> for n <- [1, 2, 3, 4], do: n * 2
[2, 4, 6, 8]

एक समझ कई जनरेटर और फिल्टर को स्वीकार करती है। अनगिनत जनरेटर का उपयोग कर परिभाषित किया जाता है <- :

# A list generator:
iex> for n <- [1, 2, 3, 4], do: n * 2
[2, 4, 6, 8]

# A comprehension with two generators
iex> for x <- [1, 2], y <- [2, 3], do: x * y
[2, 3, 4, 6]

फिल्टर भी दिए जा सकते हैं:

# A comprehension with a generator and a filter
iex> for n <- [1, 2, 3, 4, 5, 6], rem(n, 2) == 0, do: n
[2, 4, 6]

नोट जनरेटर का उपयोग फ़िल्टर करने के लिए भी किया जा सकता है क्योंकि यह किसी भी मूल्य को हटाता है जो पैटर्न के बाईं ओर से मेल नहीं खाता है <- :

iex> users = [user: "john", admin: "meg", guest: "barbara"]
iex> for {type, name} when type != :guest <- users do
...>   String.upcase(name)
...> end
["JOHN", "MEG"]

बिटस्ट्रिंग जनरेटर भी समर्थित हैं और जब आप बिटस्ट्रिंग धाराओं को व्यवस्थित करने की आवश्यकता होती है तो बहुत उपयोगी होते हैं:

iex> pixels = <<213, 45, 132, 64, 76, 32, 76, 0, 0, 234, 32, 15>>
iex> for <<r::8, g::8, b::8 <- pixels>>, do: {r, g, b}
[{213, 45, 132}, {64, 76, 32}, {76, 0, 0}, {234, 32, 15}]

समझ के अंदर परिवर्तनशील कार्य, यह जनरेटर, फिल्टर या ब्लॉक के अंदर हो, समझ के बाहर परिलक्षित नहीं होते हैं।

में

ऊपर दिए गए उदाहरणों में, समझ के द्वारा लौटाया गया परिणाम हमेशा एक सूची थी। लौटाया गया परिणाम :into विकल्प :into पास करके कॉन्फ़िगर किया जा सकता है, जो किसी भी संरचना को तब तक स्वीकार करता है जब तक वह Collectable प्रोटोकॉल को लागू करता है।

उदाहरण के लिए, हम बिटस्ट्रिंग जनरेटर का उपयोग इसके साथ कर सकते हैं :into विकल्प में आसानी से एक स्ट्रिंग में सभी रिक्त स्थान को हटाने के लिए:

iex> for <<c <- " hello world ">>, c != ?\s, into: "", do: <<c>>
"helloworld"

IO मॉड्यूल स्ट्रीम प्रदान करता है, जो कि Enumerable और Collectable दोनों हैं, यहाँ एक उच्च स्तरीय गूंज सर्वर का उपयोग किया गया है:

for line <- IO.stream(:stdio, :line), into: IO.stream(:stdio, :line) do
  String.upcase(line)
end

uniq

uniq: true यह सुनिश्चित करने के लिए समझ के लिए भी uniq: true दिया जा सकता है कि परिणाम केवल संग्रह में जोड़े गए हैं यदि वे पहले वापस नहीं किए गए थे। उदाहरण के लिए:

iex> for(x <- [1, 1, 2, 3], uniq: true, do: x * 2)
[2, 4, 6]

iex> for(<<x <- "abcabc">>, uniq: true, into: "", do: <<x - 32>>)
"ABC"

आयात (मॉड्यूल, ऑप्स) (मैक्रो)

अन्य मॉड्यूल से आयात कार्य और मैक्रोज़।

import/2 योग्य नाम का उपयोग किए बिना किसी को अन्य मॉड्यूल से फ़ंक्शन या मैक्रोज़ तक आसानी से पहुंचने की अनुमति देता है।

उदाहरण

यदि आप किसी दिए गए मॉड्यूल से कई कार्यों का उपयोग कर रहे हैं, तो आप उन कार्यों को आयात कर सकते हैं और उन्हें स्थानीय कार्यों के रूप में संदर्भित कर सकते हैं, उदाहरण के लिए:

iex> import List
iex> flatten([1, [2], 3])
[1, 2, 3]

चयनकर्ता

डिफ़ॉल्ट रूप से, एलिक्सिर दिए गए मॉड्यूल से फ़ंक्शंस और मैक्रोज़ आयात करता है, सिवाय अंडरस्कोर के साथ शुरू होने वाले (जो आमतौर पर कॉलगर्ल हैं):

import List

एक डेवलपर एकमात्र विकल्प के माध्यम से केवल मैक्रोज़ या फ़ंक्शन आयात करने के लिए फ़िल्टर कर सकता है:

import List, only: :functions
import List, only: :macros

वैकल्पिक रूप से, एलिक्जिर एक डेवलपर को :only / या :except आयात करने (या नहीं):

import List, only: [flatten: 1]
import String, except: [split: 2]

ध्यान दें कि except कॉलिंग हमेशा पहले से घोषित import/2 पर अनन्य है। यदि कोई पिछला आयात नहीं है, तो यह मॉड्यूल में सभी फ़ंक्शन और मैक्रोज़ पर लागू होता है। उदाहरण के लिए:

import List, only: [flatten: 1, keyfind: 4]
import List, except: [flatten: 1]

उपरोक्त दो आयात कॉल के बाद, केवल List.keyfind/4 को आयात किया जाएगा।

अंडरस्कोर कार्य करता है

डिफ़ॉल्ट रूप से _ साथ शुरू होने वाले फ़ंक्शन आयात नहीं किए जाते हैं। यदि आप वास्तव में _ शुरू होने वाले फ़ंक्शन को आयात करना चाहते हैं, तो आपको इसे स्पष्ट रूप से इसमें शामिल करना होगा :only चयनकर्ता।

import File.Stream, only: [__build__: 3]

लेक्सिकल स्कोप

यह ध्यान रखना महत्वपूर्ण है कि import/2 लेक्सिकल है। इसका मतलब है कि आप विशिष्ट कार्यों के अंदर विशिष्ट मैक्रो आयात कर सकते हैं:

defmodule Math do
  def some_function do
    # 1) Disable "if/2" from Kernel
    import Kernel, except: [if: 2]

    # 2) Require the new "if/2" macro from MyMacros
    import MyMacros

    # 3) Use the new macro
    if do_something, it_works
  end
end

ऊपर के उदाहरण में, हमने MyMacros से मैक्रोज़ आयात किया, मूल की जगह if/2 उस विशिष्ट फ़ंक्शन के भीतर हमारे स्वयं के कार्यान्वयन। उस मॉड्यूल में अन्य सभी फ़ंक्शन अभी भी मूल एक का उपयोग करने में सक्षम होंगे।

चेतावनी

यदि आप एक मॉड्यूल का आयात करते हैं और आप इस मॉड्यूल से किसी भी आयातित फ़ंक्शन या मैक्रोज़ का उपयोग नहीं करते हैं, तो एलिक्सिर एक चेतावनी जारी करने जा रहा है जिसका अर्थ है कि आयात का उपयोग नहीं किया जा रहा है।

यदि आयात मैक्रो द्वारा स्वचालित रूप से उत्पन्न होता है, तो अमृत स्पष्ट रूप से परिभाषित नहीं होने के बावजूद, किसी भी चेतावनी का उत्सर्जन नहीं करेगा।

दोनों चेतावनी व्यवहारों को स्पष्ट रूप से सेट करके बदला जा सकता है :warn true या false लिए :warn विकल्प।

अस्पष्ट फ़ंक्शन / मैक्रो नाम

यदि दो मॉड्यूल A और B आयात किए जाते हैं और उन दोनों में 1 की एक aroo के साथ एक foo फ़ंक्शन होता है, तो एक त्रुटि केवल तभी उत्सर्जित की जाती है जब foo/1 लिए एक अस्पष्ट कॉल वास्तव में बनाया जाता है; यही है, त्रुटियों को आलसी रूप से उत्सर्जित किया जाता है, उत्सुकता से नहीं।

भाव (opts, ब्लॉक) (मैक्रो)

किसी भी अभिव्यक्ति का प्रतिनिधित्व करता है।

उदाहरण

iex> quote do
...>   sum(1, 2, 3)
...> end
{:sum, [], [1, 2, 3]}

व्याख्या

किसी भी अमृत कोड का प्रतिनिधित्व अमृत डेटा संरचनाओं का उपयोग करके किया जा सकता है। एलिक्सिर मैक्रोज़ का बिल्डिंग ब्लॉक तीन तत्वों के साथ एक टपल है, उदाहरण के लिए:

{:sum, [], [1, 2, 3]}

ऊपर की ओर ट्यूपल 1, 2 और 3 को तर्क के रूप में पास करने के लिए एक फ़ंक्शन कॉल का प्रतिनिधित्व करता है। टपल तत्व हैं:

  • टुपल का पहला तत्व हमेशा एक ही प्रतिनिधित्व में एक परमाणु या दूसरा टपल होता है।

  • टपल का दूसरा तत्व मेटाडेटा का प्रतिनिधित्व करता है।

  • ट्यूपल का तीसरा तत्व फ़ंक्शन कॉल के लिए तर्क हैं। तीसरा तर्क एक परमाणु हो सकता है, जो आमतौर पर एक चर (या एक स्थानीय कॉल) है।

विकल्प

  • :unquote अयोग्य - जब false , अयोग्य को अक्षम करता है। उपयोगी जब आप किसी अन्य उद्धरण के अंदर एक उद्धरण रखते हैं और यह नियंत्रित करना चाहते हैं कि कौन सी बोली को अनधिकृत करने में सक्षम है।

  • :location - जब सेट किया जाता है :keep , वर्तमान लाइन और फ़ाइल को उद्धरण से रखता है। अधिक जानकारी के लिए नीचे दिए गए स्टैकट्रेस सूचना अनुभाग को पढ़ें।

  • :line - दिए गए लाइन के लिए उद्धृत भाव सेट करता है।

  • :generated - दिए गए चंक को उत्पन्न के रूप में चिह्नित करता है ताकि यह चेतावनी का उत्सर्जन न करे। वर्तमान में यह केवल विशेष रूपों पर काम करता है (उदाहरण के लिए, आप किसी case को एनोटेट कर सकते हैं लेकिन if नहीं)।

  • :context - संकल्प संदर्भ सेट करता है।

  • :bind_quoted - मैक्रो के लिए बाइंडिंग पास करता है। जब भी कोई बंधन दिया जाता है, तो unquote(expr) अपने आप अक्षम हो जाता है।

शाब्दिक अर्थ

ऊपर वर्णित टपल के अलावा, एलिक्जिर के पास कुछ शाब्दिक शब्द हैं जो उद्धृत होने पर स्वयं वापस लौटते हैं। वो हैं:

:sum         #=> Atoms
1            #=> Integers
2.0          #=> Floats
[1, 2]       #=> Lists
"strings"    #=> Strings
{key, value} #=> Tuples with two elements

उद्धरण और मैक्रोज़

quote/2 आमतौर पर कोड पीढ़ी के लिए मैक्रोज़ के साथ प्रयोग किया जाता है। एक अभ्यास के रूप में, आइए एक मैक्रो को परिभाषित करें जो एक संख्या को स्वयं (गुणा) से गुणा करता है। ध्यान दें कि मैक्रो के रूप में परिभाषित करने का कोई कारण नहीं है (और यह वास्तव में एक बुरे अभ्यास के रूप में देखा जाएगा), लेकिन यह इतना सरल है कि यह हमें उद्धरण और मैक्रोज़ के महत्वपूर्ण पहलुओं पर ध्यान केंद्रित करने की अनुमति देता है:

defmodule Math do
  defmacro squared(x) do
    quote do
      unquote(x) * unquote(x)
    end
  end
end

हम इसे इस तरह से लागू कर सकते हैं:

import Math
IO.puts "Got #{squared(5)}"

सबसे पहले, इस उदाहरण में कुछ भी नहीं है जो वास्तव में खुलासा करता है कि यह एक मैक्रो है। लेकिन क्या हो रहा है कि, संकलन के समय, squared(5) 5 * 5 हो जाता है। तर्क 5 का उत्पादन कोड में डुप्लिकेट है, हम व्यवहार में इस व्यवहार को देख सकते हैं, क्योंकि हमारे मैक्रो में वास्तव में एक बग है:

import Math
my_number = fn ->
  IO.puts "Returning 5"
  5
end
IO.puts "Got #{squared(my_number.())}"

ऊपर का उदाहरण छपेगा:

Returning 5
Returning 5
Got 25

ध्यान दें कि कैसे "रिटर्निंग 5" सिर्फ एक बार के बजाय दो बार मुद्रित किया गया था। ऐसा इसलिए है क्योंकि एक मैक्रो एक अभिव्यक्ति प्राप्त करता है और एक मूल्य नहीं (जो हम एक नियमित कार्य में उम्मीद करेंगे)। इस का मतलब है कि:

squared(my_number.())

वास्तव में:

my_number.() * my_number.()

जो दो बार फ़ंक्शन को आमंत्रित करता है, यह समझाता है कि हमें दो बार मुद्रित मूल्य क्यों मिलता है! अधिकांश मामलों में, यह वास्तव में अनपेक्षित व्यवहार है, और इसीलिए मैक्रों की बात आते ही आपको सबसे पहले एक बात ध्यान में रखनी होगी कि एक ही मूल्य को एक से अधिक बार न समझना

चलो हमारे मैक्रो को ठीक करें:

defmodule Math do
  defmacro squared(x) do
    quote do
      x = unquote(x)
      x * x
    end
  end
end

अब इनवॉइसिंग squared(my_number.()) पहले की ही तरह एक बार वैल्यू प्रिंट करेगा।

वास्तव में, यह पैटर्न इतना सामान्य है कि अधिकांश बार आप quote/2 साथ bind_quoted विकल्प का उपयोग करना bind_quoted :

defmodule Math do
  defmacro squared(x) do
    quote bind_quoted: [x: x] do
      x * x
    end
  end
end

:bind_quoted उपरोक्त उदाहरण के समान कोड में अनुवाद करेगा। :bind_quoted का उपयोग कई मामलों में किया जा सकता है और इसे अच्छे अभ्यास के रूप में देखा जाता है, न केवल इसलिए क्योंकि यह हमें सामान्य गलतियों में भाग जाने से रोकने में मदद करता है, बल्कि इसलिए भी कि यह हमें मैक्रोज़ द्वारा उजागर किए गए अन्य साधनों का लाभ उठाने की अनुमति देता है, जैसे कि कुछ खंडों में चर्चा किए गए unquote टुकड़े। नीचे।

इस संक्षिप्त परिचय को समाप्त करने से पहले, आप देखेंगे कि भले ही हमने अपनी बोली के अंदर एक चर x को परिभाषित किया हो:

quote do
  x = unquote(x)
  x * x
end

जब हम कॉल करते हैं:

import Math
squared(5)
x #=> ** (CompileError) undefined variable x or undefined function x/0

हम देख सकते हैं कि x उपयोगकर्ता के संदर्भ में लीक नहीं हुआ था। ऐसा इसलिए होता है क्योंकि अमृत मैक्रोज़ हाइजेनिक हैं, एक ऐसा विषय जिस पर हम अगले खंडों में भी चर्चा करेंगे।

चर में स्वच्छता

निम्नलिखित उदाहरण पर विचार करें:

defmodule Hygiene do
  defmacro no_interference do
    quote do
      a = 1
    end
  end
end

require Hygiene

a = 10
Hygiene.no_interference
a #=> 10

ऊपर दिए गए उदाहरण में, 10 रिटर्न भले ही मैक्रो स्पष्ट रूप से 1 पर सेट कर रहा हो क्योंकि मैक्रो में परिभाषित चर उस संदर्भ को प्रभावित नहीं करते हैं जिसमें मैक्रो निष्पादित होता है। यदि आप कॉलर के संदर्भ में एक चर सेट या प्राप्त करना चाहते हैं, तो आप var! की मदद से कर सकते हैं var! मैक्रो:

defmodule NoHygiene do
  defmacro interference do
    quote do
      var!(a) = 1
    end
  end
end

require NoHygiene

a = 10
NoHygiene.interference
a #=> 1

ध्यान दें कि आप एक ही मॉड्यूल में परिभाषित चर तक भी नहीं पहुँच सकते हैं जब तक कि आप स्पष्ट रूप से इसे एक संदर्भ न दें:

defmodule Hygiene do
  defmacro write do
    quote do
      a = 1
    end
  end

  defmacro read do
    quote do
      a
    end
  end
end

Hygiene.write
Hygiene.read
#=> ** (RuntimeError) undefined variable a or undefined function a/0

ऐसे के लिए, आप तर्क के रूप में स्पष्ट रूप से वर्तमान मॉड्यूल गुंजाइश पारित कर सकते हैं:

defmodule ContextHygiene do
  defmacro write do
    quote do
      var!(a, ContextHygiene) = 1
    end
  end

  defmacro read do
    quote do
      var!(a, ContextHygiene)
    end
  end
end

ContextHygiene.write
ContextHygiene.read
#=> 1

उपनामों में स्वच्छता

बोली के अंदर उपनाम डिफ़ॉल्ट रूप से स्वच्छ हैं। निम्नलिखित उदाहरण पर विचार करें:

defmodule Hygiene do
  alias Map, as: M

  defmacro no_interference do
    quote do
      M.new
    end
  end
end

require Hygiene
Hygiene.no_interference #=> %{}

ध्यान दें कि, भले ही उपनाम M संदर्भ में उपलब्ध नहीं है, मैक्रो का विस्तार किया गया है, उपरोक्त कोड काम करता है क्योंकि M अभी भी Map फैलता है।

इसी तरह, भले ही हम मैक्रो को लागू करने से पहले एक ही नाम के साथ एक उपनाम परिभाषित करते हैं, यह मैक्रो के परिणाम को प्रभावित नहीं करेगा:

defmodule Hygiene do
  alias Map, as: M

  defmacro no_interference do
    quote do
      M.new
    end
  end
end

require Hygiene
alias SomethingElse, as: M
Hygiene.no_interference #=> %{}

कुछ मामलों में, आप एक उपनाम या कॉलर में परिभाषित एक मॉड्यूल का उपयोग करना चाहते हैं। इस तरह के लिए, आप alias! उपयोग कर सकते हैं alias! मैक्रो:

defmodule Hygiene do
  # This will expand to Elixir.Nested.hello
  defmacro no_interference do
    quote do
      Nested.hello
    end
  end

  # This will expand to Nested.hello for
  # whatever is Nested in the caller
  defmacro interference do
    quote do
      alias!(Nested).hello
    end
  end
end

defmodule Parent do
  defmodule Nested do
    def hello, do: "world"
  end

  require Hygiene
  Hygiene.no_interference
  #=> ** (UndefinedFunctionError) ...

  Hygiene.interference
  #=> "world"
end

आयात में स्वच्छता

उपनाम के समान, अमृत में आयात स्वच्छ हैं। निम्नलिखित कोड पर विचार करें:

defmodule Hygiene do
  defmacrop get_length do
    quote do
      length([1, 2, 3])
    end
  end

  def return_length do
    import Kernel, except: [length: 1]
    get_length
  end
end

Hygiene.return_length #=> 3

ध्यान दें कि फ़ंक्शन आयात नहीं होने के बावजूद कैसे Hygiene.return_length/0 रिटर्न करता है। वास्तव में, भले ही किसी अन्य मॉड्यूल से समान नाम और अर्थ के साथ एक फ़ंक्शन आयात किया जाए, यह फ़ंक्शन परिणाम को प्रभावित नहीं करेगा: 3 Kernel.length/1 return_length/0

def return_length do
  import String, only: [length: 1]
  get_length
end

इस नए return_length/0 को कॉल करने पर 3 परिणाम के रूप में वापस आ जाएगा ।

नवीनतम संभावित क्षण में देरी करने के लिए अमृत काफी स्मार्ट है। इसलिए, यदि आप length([1, 2, 3]) उद्धरण के अंदर कॉल करते हैं, लेकिन कोई Kernel.length/1 फ़ंक्शन उपलब्ध नहीं है, तो यह कॉलर में विस्तारित होता है:

defmodule Lazy do
  defmacrop get_length do
    import Kernel, except: [length: 1]

    quote do
      length("hello")
    end
  end

  def return_length do
    import Kernel, except: [length: 1]
    import String, only: [length: 1]
    get_length
  end
end

Lazy.return_length #=> 5

ढेर जानकारी

मैक्रोज़ के माध्यम से फ़ंक्शन को परिभाषित करते समय, डेवलपर्स के पास यह चुनने का विकल्प होता है कि रनटाइम त्रुटियों को कॉलर से या उद्धरण के अंदर से रिपोर्ट किया जाएगा। आइए एक उदाहरण देखें:

# adder.ex
defmodule Adder do
  @doc "Defines a function that adds two numbers"
  defmacro defadd do
    quote location: :keep do
      def add(a, b), do: a + b
    end
  end
end

# sample.ex
defmodule Sample do
  import Adder
  defadd
end

require Sample
Sample.add(:one, :two)
#=> ** (ArithmeticError) bad argument in arithmetic expression
#=>     adder.ex:5: Sample.add/2

जब उपयोग location: :keep और अमान्य तर्क दिए जाते हैं Sample.add/2 , तो स्टैकट्रेस जानकारी फ़ाइल और पंक्ति के अंदर इंगित होगी। इसके बिना location: :keep , त्रुटि को रिपोर्ट किया defadd गया था जहां पर लागू किया गया था। नोट location: :keep बोली के अंदर केवल परिभाषाओं को प्रभावित करता है।

बाइंडिंग और टुकड़े टुकड़े करना

अमृत ​​उद्धरण / निर्विवाद तंत्र एक कार्यक्षमता प्रदान करता है जिसे निर्विवाद अंश कहा जाता है। फ़ुटपाथ पर फ़ंक्शंस उत्पन्न करने के लिए अनचाहे टुकड़े आसान तरीका प्रदान करते हैं। इस उदाहरण पर विचार करें:

kv = [foo: 1, bar: 2]
Enum.each kv, fn {k, v} ->
  def unquote(k)(), do: unquote(v)
end

ऊपर के उदाहरण में, हमने फ़ंक्शन foo/0 और bar/0 गतिशील रूप से उत्पन्न किया है । अब, कल्पना कीजिए कि, हम इस कार्यक्षमता को एक मैक्रो में बदलना चाहते हैं:

defmacro defkv(kv) do
  Enum.map kv, fn {k, v} ->
    quote do
      def unquote(k)(), do: unquote(v)
    end
  end
end

हम इस मैक्रो को इस तरह से लागू कर सकते हैं:

defkv [foo: 1, bar: 2]

हालाँकि, हम इसे इस प्रकार नहीं भेज सकते हैं:

kv = [foo: 1, bar: 2]
defkv kv

ऐसा इसलिए है क्योंकि मैक्रो संकलन समय पर एक कीवर्ड सूची होने के लिए अपने तर्कों की उम्मीद कर रहा है । चूंकि ऊपर के उदाहरण में हम चर का प्रतिनिधित्व कर रहे हैं kv , इसलिए हमारा कोड विफल हो गया है।

मैक्रोज़ को विकसित करते समय यह वास्तव में एक सामान्य नुकसान है। हम स्थूल में एक विशेष आकार मान रहे हैं। हम उद्धृत अभिव्यक्ति के अंदर चर को हटाकर इसके चारों ओर काम कर सकते हैं:

defmacro defkv(kv) do
  quote do
    Enum.each unquote(kv), fn {k, v} ->
      def unquote(k)(), do: unquote(v)
    end
  end
end

आप हमारे नए मैक्रो चलाने का प्रयास करते हैं, तो आप यह भी संकलन नहीं होगा नोटिस करेंगे, शिकायत है कि चर k और v मौजूद नहीं हैं। यह अस्पष्टता के कारण है: unquote(k) या तो एक पूर्ववत खंड हो सकता है, जैसा कि पहले था, या में नियमित रूप से निर्विवाद रूप से unquote(kv)

इस समस्या का एक समाधान मैक्रो में unquoting को अक्षम करना है, हालांकि, ऐसा करना kv पेड़ में प्रतिनिधित्व को इंजेक्ट करना असंभव बना देगा । जब :bind_quoted विकल्प बचाव में आता है (फिर से!)। :bind_quoted पेड़ में वांछित चर इंजेक्ट करते हुए , हम स्वचालित रूप से निर्विवाद रूप से अक्षम कर सकते हैं:

defmacro defkv(kv) do
  quote bind_quoted: [kv: kv] do
    Enum.each kv, fn {k, v} ->
      def unquote(k)(), do: unquote(v)
    end
  end
end

वास्तव में, :bind_quoted विकल्प की सिफारिश की जाती है कि हर बार एक मूल्य को बोली में इंजेक्ट करने की इच्छा हो।

प्राप्त करें (args) (मैक्रो)

जाँचता है कि क्या वर्तमान प्रक्रिया मेलबॉक्स में दिए गए खंडों से मेल खाता कोई संदेश है।

यदि ऐसा कोई संदेश नहीं है, तो वर्तमान प्रक्रिया तब तक लटकी रहती है जब तक कि कोई संदेश नहीं आता है या किसी दिए गए टाइमआउट मूल्य तक इंतजार नहीं करता है।

उदाहरण

receive do
  {:selector, number, name} when is_integer(number) ->
    name
  name when is_atom(name) ->
    name
  _ ->
    IO.puts :stderr, "Unexpected message received"
end

after दी गई समयावधि के बाद, मिलीसेकंड में निर्दिष्ट संदेश प्राप्त नहीं होने की स्थिति में एक वैकल्पिक क्लॉज दिया जा सकता है:

receive do
  {:selector, number, name} when is_integer(number) ->
    name
  name when is_atom(name) ->
    name
  _ ->
    IO.puts :stderr, "Unexpected message received"
after
  5000 ->
    IO.puts :stderr, "No message in 5 seconds"
end

after खंड भले ही कोई मैच खंड हैं निर्दिष्ट किया जा सकता। after अनुमत मानों में से किसी एक का मूल्यांकन करने के लिए दिया गया टाइमआउट मान हो सकता है:

  • :infinity - प्रक्रिया को एक मेल संदेश के लिए अनिश्चित काल तक प्रतीक्षा करनी चाहिए, यह वही है जो आफ्टर क्लॉज का उपयोग नहीं करता है

  • 0 - यदि मेलबॉक्स में कोई मेल संदेश नहीं है, तो टाइमआउट तुरंत होगा

  • पॉजिटिव पूर्णांक से छोटा या इसके बराबर 4_294_967_295 ( 0xFFFFFFFF हेक्साडेसिमल नोटेशन में) - यह अहस्ताक्षरित 32-बिट पूर्णांक के रूप में टाइमआउट मान का प्रतिनिधित्व करना संभव होना चाहिए।

चर संभालना

receive(args) विशेष रूप बिल्कुल के रूप में चर संभालती case/2 विशेष मैक्रो। अधिक जानकारी के लिए, डॉक्स की जांच करें case/2

आवश्यकता (मॉड्यूल, ऑप्स) (मैक्रो)

इसके मैक्रोज़ का उपयोग करने के लिए एक मॉड्यूल की आवश्यकता होती है।

उदाहरण

मॉड्यूल में सार्वजनिक कार्य विश्व स्तर पर उपलब्ध हैं, लेकिन मैक्रोज़ का उपयोग करने के लिए, आपको उस मॉड्यूल की आवश्यकता होती है जिसमें उन्हें परिभाषित किया गया हो।

मान लीजिए कि आपने if/2 मॉड्यूल में अपना कार्यान्वयन बनाया है MyMacros । यदि आप इसे लागू करना चाहते हैं, तो आपको पहले स्पष्ट रूप से इसकी आवश्यकता होगी MyMacros :

defmodule Math do
  require MyMacros
  MyMacros.if do_something, it_works
end

मैक्रो को कॉल करने का प्रयास जो लोड नहीं किया गया था, एक त्रुटि बढ़ाएगा।

उपनाम शॉर्टकट

require/2 यह भी as: एक विकल्प के रूप में स्वीकार करता है तो यह स्वचालित रूप से एक उपनाम सेट करता है। कृपया alias/2 अधिक जानकारी के लिए जाँच करें ।

सुपर (आर्ग्स) (मैक्रो)

ओवरराइड फ़ंक्शन को कॉल करता है जब इसके साथ ओवरराइड किया जाता है Kernel.defoverridable/1

Kernel.defoverridable/1 अधिक जानकारी और प्रलेखन के लिए देखें ।

प्रयास करें (args) (मैक्रो)

दिए गए भावों का मूल्यांकन करता है और किसी भी त्रुटि, निकास, या फेंकने वाले को संभालता है।

उदाहरण

try do
  do_something_that_may_fail(some_arg)
rescue
  ArgumentError ->
    IO.puts "Invalid argument given"
catch
  value ->
    IO.puts "Caught #{inspect(value)}"
else
  value ->
    IO.puts "Success! The result was #{inspect(value)}"
after
  IO.puts "This is printed regardless if it failed or succeed"
end

rescue खंड अपवाद को संभालने के लिए प्रयोग किया जाता है, जबकि catch खंड फेंक दिया मूल्यों और बाहर निकलता है पकड़ने के लिए इस्तेमाल किया जा सकता। else खंड अभिव्यक्ति का परिणाम के आधार पर प्रवाह को नियंत्रित करने के लिए इस्तेमाल किया जा सकता है। catch , rescue और else उपवाक्य पैटर्न मिलान ( case विशेष रूप के समान ) के आधार पर काम करते हैं ।

ध्यान दें कि try(args) एक अपवाद होने की स्थिति में वीएम को स्टैकट्रेस रखने की आवश्यकता होने पर कॉल पुनरावर्ती नहीं होती है। स्टैकट्रेस को पुनः प्राप्त करने के लिए, या क्लॉज के __STACKTRACE__ अंदर पहुंचें । rescue catch

rescue खंड

पैटर्न मिलान पर भरोसा करने के अलावा, rescue खंड अपवादों के आसपास कुछ उपयुक्तता प्रदान करते हैं जो किसी को इसके नाम से अपवाद को बचाने की अनुमति देते हैं। निम्नलिखित सभी प्रारूप rescue खंडों में मान्य पैटर्न हैं:

# Rescue a single exception without binding the exception
# to a variable
try do
  UndefinedModule.undefined_function
rescue
  UndefinedFunctionError -> nil
end

# Rescue any of the given exception without binding
try do
  UndefinedModule.undefined_function
rescue
  [UndefinedFunctionError, ArgumentError] -> nil
end

# Rescue and bind the exception to the variable "x"
try do
  UndefinedModule.undefined_function
rescue
  x in [UndefinedFunctionError] -> nil
end

# Rescue all kinds of exceptions and bind the rescued exception
# to the variable "x"
try do
  UndefinedModule.undefined_function
rescue
  x -> nil
end

एरलैंग त्रुटियां

Erlang त्रुटियों को अमृत में बदल दिया जाता है जब बचाव करते हैं:

try do
  :erlang.error(:badarg)
rescue
  ArgumentError -> :ok
end
#=> :ok

सबसे आम Erlang त्रुटियों को उनके अमृत समकक्ष में बदल दिया जाएगा। जो अधिक सामान्य में रूपांतरित नहीं होंगे ErlangError :

try do
  :erlang.error(:unknown)
rescue
  ErlangError -> :ok
end
#=> :ok

वास्तव में, ErlangError किसी भी त्रुटि का बचाव करने के लिए इस्तेमाल किया जा सकता है जो एक उचित अमृत त्रुटि नहीं है। उदाहरण के लिए, इसका उपयोग :badarg परिवर्तन से पहले की गई त्रुटि को भी ठीक करने के लिए किया जा सकता है :

try do
  :erlang.error(:badarg)
rescue
  ErlangError -> :ok
end
#=> :ok

catch खंड

catch खंड फेंक दिया मूल्यों, बाहर निकलता है, और त्रुटियों को पकड़ने के लिए इस्तेमाल किया जा सकता।

फेंके गए मूल्यों को पकड़ना

catch द्वारा फेंके गए मूल्यों को पकड़ने के लिए इस्तेमाल किया जा सकता है Kernel.throw/1 :

try do
  throw(:some_value)
catch
  thrown_value ->
    IO.puts "A value was thrown: #{inspect(thrown_value)}"
end

किसी भी तरह के मूल्यों को पकड़ना

catch खंड भी बाहर निकलता है और त्रुटियों को पकड़ने का समर्थन करता है। ऐसा करने के लिए, यह दोनों पर मिलान की अनुमति देता है तरह पकड़ा मूल्य के रूप में अच्छी तरह के रूप में मूल्य:

try do
  exit(:shutdown)
catch
  :exit, value
    IO.puts "Exited with value #{inspect(value)}"
end

try do
  exit(:shutdown)
catch
  kind, value when kind in [:exit, :throw] ->
    IO.puts "Caught exit or throw with value #{inspect(value)}"
end

catch खंड भी समर्थन करता है, :error के साथ-साथ :exit और :throw , Erlang में के रूप में हालांकि यह आमतौर पर के पक्ष में से बचा जाता है raise / rescue नियंत्रण तंत्र। इसका एक कारण यह है कि पकड़ते समय :error , त्रुटि स्वचालित रूप से एक अमृत त्रुटि में तब्दील नहीं होती है:

try do
  :erlang.error(:badarg)
catch
  :error, :badarg -> :ok
end
#=> :ok

after खंड

एक after क्लॉज आपको क्लीनअप लॉजिक को परिभाषित करने की अनुमति देता है जो कोड के ब्लॉक को try(args) सफल होने के लिए और किसी त्रुटि के उठाए जाने पर भी दोनों को लागू किया जाएगा । ध्यान दें कि एग्जिट सिग्नल प्राप्त करते समय प्रक्रिया सामान्य रूप से बाहर निकल जाएगी जो इसे अचानक से बाहर निकलने का कारण बनती है और इसलिए after क्लॉज को निष्पादित करने की गारंटी नहीं है। सौभाग्य से, एलिक्सिर में अधिकांश संसाधन (जैसे खुली फाइलें, ईटीएस टेबल, पोर्ट, सॉकेट, और इतने पर) खुद को जोड़ने की प्रक्रिया से जुड़े होते हैं या निगरानी करते हैं और स्वचालित रूप से उस प्रक्रिया से बाहर निकलने पर खुद को साफ कर लेंगे।

File.write!("tmp/story.txt", "Hello, World")
try do
  do_something_with("tmp/story.txt")
after
  File.rm("tmp/story.txt")
end

else खंड

else क्लॉज, शरीर के परिणाम को try(args) पैटर्न से मेल खाने की अनुमति देता है:

x = 2
try do
  1 / x
rescue
  ArithmeticError ->
    :infinity
else
  y when y < 1 and y > -1 ->
    :small
  _ ->
    :large
end

यदि कोई else खंड मौजूद नहीं है और कोई अपवाद नहीं उठाया गया है, तो अभिव्यक्ति का परिणाम वापस आ जाएगा:

x = 1
^x =
  try do
    1 / x
  rescue
    ArithmeticError ->
      :infinity
  end

हालांकि, जब कोई else खंड मौजूद होता है लेकिन अभिव्यक्ति का परिणाम किसी भी पैटर्न से मेल नहीं खाता है तो एक अपवाद उठाया जाएगा। यह अपवाद एक catch या एक rescue ही द्वारा पकड़ा नहीं जाएगा try :

x = 1
try do
  try do
    1 / x
  rescue
    # The TryClauseError cannot be rescued here:
    TryClauseError ->
      :error_a
  else
    0 ->
      :small
  end
rescue
  # The TryClauseError is rescued here:
  TryClauseError ->
    :error_b
end

इसी तरह, एक else खंड के अंदर एक अपवाद पकड़ा या उसी के अंदर बचाया नहीं है try :

try do
  try do
    nil
  catch
    # The exit(1) call below can not be caught here:
    :exit, _ ->
      :exit_a
  else
    _ ->
      exit(1)
  end
catch
  # The exit is caught here:
  :exit, _ ->
    :exit_b
end

इसका मतलब यह है कि वीएम को अब एक else क्लॉज के अंदर एक बार स्टैकट्रेस रखने की जरूरत नहीं होती है और इसलिए try टेल कॉल को अंतिम कॉल के रूप में एक कॉल के साथ प्रयोग करते समय टेल रीसर्शन संभव है else । उसी के लिए सच है rescue और catch खंड।

केवल कोशिश की गई अभिव्यक्ति का परिणाम else खंड तक गिर जाता है । यदि try अंत rescue या catch खंड में समाप्त होता है , तो उनका परिणाम नीचे नहीं आएगा else :

try do
  throw(:catch_this)
catch
  :throw, :catch_this ->
    :it_was_caught
else
  # :it_was_caught will not fall down to this "else" clause.
  other ->
    {:else, other}
end

परिवर्तनशील हैंडलिंग

चूँकि एक try अपवाद के कारण अंदर की अभिव्यक्ति का मूल्यांकन try नहीं किया जा सकता है, इसलिए अंदर बनाया गया कोई भी चर बाहरी रूप से नहीं देखा जा सकता है। उदाहरण के लिए:

try do
  x = 1
  do_something_that_may_fail(same_arg)
  :ok
catch
  _, _ -> :failed
end

x #=> unbound variable "x"

ऊपर दिए गए उदाहरण में, x इसे एक्सेस नहीं किया जा सकता क्योंकि यह try क्लॉज के अंदर परिभाषित किया गया था । इस समस्या को हल करने के लिए एक आम बात यह है कि अंदर परिभाषित चर वापस करना है try :

x =
  try do
    x = 1
    do_something_that_may_fail(same_arg)
    x
  catch
    _, _ -> :failed
  end

निर्विवाद (expr) (मैक्रो)

किसी मैक्रो के अंदर से दी गई अभिव्यक्ति को रेखांकित करता है।

उदाहरण

उस स्थिति की कल्पना करें जो आपके पास एक चर है value और आप इसे कुछ उद्धरण के अंदर इंजेक्ट करना चाहते हैं। पहला प्रयास होगा:

value = 13
quote do
  sum(1, value, 3)
end

जो फिर वापस आ जाएगी:

{:sum, [], [1, {:value, [], quoted}, 3]}

जो अपेक्षित परिणाम नहीं है। इसके लिए, हम अयोग्य का उपयोग करते हैं:

iex> value = 13
iex> quote do
...>   sum(1, unquote(value), 3)
...> end
{:sum, [], [1, 13, 3]}

unquote_splicing (expr) (मैक्रो)

दी गई सूची को अपने तर्कों का विस्तार करते हुए रेखांकित करता है। के समान unquote(expr)

उदाहरण

iex> values = [2, 3, 4]
iex> quote do
...>   sum(1, unquote_splicing(values), 5)
...> end
{:sum, [], [1, 2, 3, 4, 5]}

(args) (मैक्रो) के साथ

मिलान किए गए खंडों को संयोजित करने के लिए उपयोग किया जाता है।

एक उदाहरण से शुरू करते हैं:

iex> opts = %{width: 10, height: 15}
iex> with {:ok, width} <- Map.fetch(opts, :width),
...>      {:ok, height} <- Map.fetch(opts, :height) do
...>   {:ok, width * height}
...> end
{:ok, 150}

यदि सभी क्लॉज़ मेल खाते हैं, तो do ब्लॉक को निष्पादित किया जाता है, इसका परिणाम लौटाता है। अन्यथा चेन निरस्त कर दी जाती है और गैर-मिलान किया गया मान लौटा दिया जाता है:

iex> opts = %{width: 10}
iex> with {:ok, width} <- Map.fetch(opts, :width),
...>      {:ok, height} <- Map.fetch(opts, :height) do
...>   {:ok, width * height}
...> end
:error

गार्ड पैटर्न में भी इस्तेमाल किया जा सकता है:

iex> users = %{"melany" => "guest", "bob" => :admin}
iex> with {:ok, role} when not is_binary(role) <- Map.fetch(users, "bob") do
...>   {:ok, to_string(role)}
...> end
{:ok, "admin"}

के रूप में for(args) , अंदर बंधे चर with(args) लीक नहीं होंगे; "नंगे भाव" को क्लाज के बीच भी डाला जा सकता है:

iex> width = nil
iex> opts = %{width: 10, height: 15}
iex> with {:ok, width} <- Map.fetch(opts, :width),
...>      double_width = width * 2,
...>      {:ok, height} <- Map.fetch(opts, :height) do
...>   {:ok, double_width * height}
...> end
{:ok, 300}
iex> width
nil

ध्यान दें कि यदि "नंगे अभिव्यक्ति" मेल करने में विफल रहता है, तो यह MatchError गैर-मिलान किए गए मान को वापस करने के बजाय बढ़ाएगा :

with :foo = :bar, do: :ok
#=> ** (MatchError) no match of right hand side value: :bar

एलिक्ज़िर में किसी अन्य फ़ंक्शन या मैक्रो कॉल के साथ, स्पष्ट परेंस का उपयोग do / end ब्लॉक से पहले तर्कों के आसपास भी किया जा सकता है :

iex> opts = %{width: 10, height: 15}
iex> with(
...>   {:ok, width} <- Map.fetch(opts, :width),
...>   {:ok, height} <- Map.fetch(opts, :height)
...> ) do
...>   {:ok, width * height}
...> end
{:ok, 150}

Parens और नहीं Parens के बीच चुनाव प्राथमिकता का विषय है।

असफल मैच के मामले में जो else लौटाया जा रहा है उसे संशोधित करने के लिए एक विकल्प दिया जा सकता है with :

iex> opts = %{width: 10}
iex> with {:ok, width} <- Map.fetch(opts, :width),
...>      {:ok, height} <- Map.fetch(opts, :height) do
...>   {:ok, width * height}
...> else
...>   :error ->
...>     {:error, :wrong_data}
...> end
{:error, :wrong_data}

यदि कोई मिलान की else स्थिति नहीं है, तो एक WithClauseError अपवाद उठाया जाता है।

{args} (मैक्रो)

टपल बनाता है।

ट्यूपल डेटा प्रकार के बारे में और ट्यूपल्स में हेरफेर करने के कार्यों के बारे में अधिक जानकारी Tuple मॉड्यूल में मिल सकती है ; टुपल्स के साथ काम करने के लिए कुछ फ़ंक्शन भी उपलब्ध हैं Kernel (जैसे Kernel.elem/2 या Kernel.tuple_size/1 )।

एएसटी प्रतिनिधित्व

एलिक्जिर में केवल दो-आइटम टुपल्स को शाब्दिक माना जाता है और उद्धृत किए जाने पर स्वयं वापस आ जाते हैं। इसलिए, :{} विशेष रूप में कॉल के रूप में एएसटी में अन्य सभी टुपल्स का प्रतिनिधित्व किया जाता है ।

iex> quote do
...>   {1, 2}
...> end
{1, 2}

iex> quote do
...>   {1, 2, 3}
...> end
{:{}, [], [1, 2, 3]}

Original text