Kurzusok
/
Crystal
Crystal
/
Tanterv
/
Procok és blokkok
Pr

Procok és blokkok ebben a kurzusban: Crystal

1 feladat

A(z) Procok és blokkok fogalomról

A block egy kódrészlet, amely átadható egy metódusnak. Más programozási nyelvekben ezt névtelen függvénynek vagy lambdának nevezik. Egy metódus a blockot Proc típusúvá alakíthatja, amely egy kódrészletet reprezentál.

def my_method(&block)
  1 + yield
end

my_method { 2 }
# => 3

A blockokat és a Procokat nagyon gyakran használják a Crystalban, például iterációhoz és visszahívásokhoz, de DSL-ek (domain-specifikus nyelvek) létrehozására is. A DSL-ek néhány példája a Kemal webes keretrendszer vagy a Spec tesztkeretrendszer (ezzel tesztelik a Crystal-megoldásaidat).

Blockok

Ahhoz, hogy olyan metódust hozz létre, amely elfogad egy blockot, az utolsó argumentum elé egy és-jelet (&) kell tenned. Ez a blockot Proccá alakítja, és hozzárendeli az argumentumhoz. Ezután a yield használatával végrehajtod a metódusnak átadott blockot.

def my_method(&block)
  1 + yield
end

Block átadására kétféle mód van: vagy a do ... end kulcsszavakkal, vagy kapcsos zárójelekkel ({}). A kettő közti fő különbség a precedencia: a do ... end támogatja a többsoros blockokat, a kapcsos zárójel ({}) viszont nem.

my_method do
  2
end
# => 3

my_method { 2 }
# => 3

Yield

A yield egy kulcsszó, amely végrehajtja a metódusnak átadott blockot. Ez azt jelenti, hogy a block soha nem fut le, ha nem hívod meg a yield-et. Argumentumokat is kaphat, amelyeket átad a blocknak. Nincs korlát arra, hány argumentumot lehet átadni a blocknak. Ha a blockban szeretnéd használni az argumentumokat, a |x, y, ...| szintaxist használod. Itt az x, y, ... az argumentumok nevei.

def my_method(&block)
  1 + yield 2
end

# With curly braces:

my_method { |x| x * 3 }
# => 7

# With do ... end:

my_method do |x|
  x * 3
end
# => 7

A fenti példában a block a 2 argumentumot kapja, majd megszorozza 3-mal, és 6-ot ad vissza. Ezután a metódus 1-et ad az eredményhez, és 7-et ad vissza.

Ha a yield-nek adott argumentumok száma több, mint amennyit a block vár, hiba keletkezik.

def my_method(&block)
  1 + yield
end

my_method { |x| x * 3 }
# Error: too many block parameters (given 1, expected maximum 0)

A blockok típusai

A blockokat megírhatod explicit vagy implicit módon. Az implicit blockok a leggyakoribbak, és a fenti példákban ilyeneket láttál. Sőt, adhatsz a blocknak különböző típusú argumentumokat is; a fordító kikövetkezteti a típusokat, és egy uniótípust hoz létre.

def my_method(&block)
  yield "a"
  yield 1
end

my_method do |x|
  p typeof(x)
end

# output: (String | Int32)

Az explicit blockok írásakor megadhatod az argumentumok típusait és a visszatérési típust. Ezt az Arg1Type, Arg2Type, ... -> ResultType szintaxis teszi lehetővé. Itt az argumentumokat vessző (,), a visszatérési típust pedig -> választja el.

def my_method(&block : Int32, Int32 -> Int32)
  1 + yield(2, 3)
end

my_method { |x, y| x * y }
# => 7

Ahogy más explicit típusoknál, a fordító itt is kikényszeríti, hogy a típusok a vártnak megfelelőek legyenek. Ha a block nem egyezik a metódusnak megadott típussal, hiba keletkezik.

Rövidített szintaxis

Van egy rövidített szintaxis az olyan blockokhoz, amelyek csak egy argumentumot vesznek át, és csak egy metódust hívnak meg rajta. A |x| helyett a & jelet használhatod az argumentum neve előtt.

def my_method(&block)
  yield "a"
end

# This is: 

my_method { |x| x.upcase }
# => "A"

# Is the same as:

my_method &.upcase
# => "A"

Procok

A Proc nagyon szorosan kapcsolódik a blockokhoz. A fő különbség az, hogy a Proc egy típus, a block pedig nem. A Proc egy függvénymutatót reprezentál, és változóként is átadható.

Egy Proc definiálásához a ->(args) { ... } proc literál szintaxist használod. Az argumentumokat vessző (,), a blockot { ... } választja el. Egy Proc meghívásához a call metódust használod, és átadod neki az argumentumokat. A paraméterek típusai kötelezőek. A visszatérési típust a proc törzse alapján következteti ki a fordító, de explicit módon is megadható.

my_proc = ->(x : Int32, y : Int32) : Int32 { x * y }
my_proc.call(2, 3)
# => 6

Blockok rögzítése

A blockok rögzítése egy módja annak, hogy Proc-vá alakíts egy blockot. Ehhez a & operátort kell használnod a metódus utolsó argumentuma előtt. Ez a blockot Proc-vá alakítja, és hozzárendeli az argumentumhoz.

def my_method(&block)
  block.call
end

my_method { 1 + 2 }
# => 3

Procok átadása metódusoknak

A Procok átadhatók olyan metódusoknak, amelyek blockot várnak. Ez akkor lehet hasznos, ha valamilyen feltételtől függően más-más blockot szeretnél átadni.

def my_method(&block)
  yield 5
end

my_proc = -> (x) { x * 2 }
my_method(&my_proc)
# => 10

Változók típusának deklarálása

Egy változó deklarálásakor a : Type szintaxissal adhatod meg a változó típusát. Procok esetén a Proc((ArgType, ...), ResultType) szintaxist használod. Az utolsó típus mindig a visszatérési típus, a többi pedig az argumentumok típusa. Ez azt jelenti, hogy ha csak egy típus van, az a visszatérési típus lesz, és a proc nem vesz át argumentumot.

my_proc : Proc(Int32, Int32, Int32) = ->(x, y) { x * y }
other_proc : Proc(Int32) = -> { 1 }

Procok deklarálása metódusokból

Egy metódusból is deklarálhatsz procot.

def my_method(a, b)
  a + b
end

my_proc = ->my_method(Int32, Int32)
my_proc.call(2, 3)
Szerkesztés GitHubon A hivatkozás új ablakban vagy lapon nyílik meg

Tanuld meg a(z) Procok és blokkok fogalmat

A gyakorlás zárolva

Oldj fel még 1 feladatot, hogy gyakorolhasd a(z) Procok és blokkok fogalmat