Lukninger i Groovy

1. Oversigt

I denne introduktionsvejledning undersøger vi begrebet lukninger i Groovy, et nøglefunktion i dette dynamiske og kraftfulde JVM-sprog.

Mange andre sprog, herunder Javascript og Python, understøtter begrebet lukninger. Lukningens karakteristika og funktion varierer dog fra sprog til sprog.

Vi berører vigtige aspekter af Groovy-lukninger og viser eksempler på, hvordan de bruges undervejs.

2. Hvad er en lukning?

En lukning er en anonym blok af kode. I Groovy er det en forekomst af Lukning klasse. Lukninger kan tage 0 eller flere parametre og returnerer altid en værdi.

Derudover kan en lukning få adgang til omgivende variabler uden for dets anvendelsesområde og bruge dem - sammen med dens lokale variabler - under udførelse.

Desuden kan vi tildele en lukning til en variabel eller videregive den som en parameter til en metode. Derfor giver en lukning funktionalitet til forsinket udførelse.

3. Lukningserklæring

En groovy lukning indeholder parametre, pilen -> og koden, der skal udføres. Parametre er valgfri, og hvis de er angivet, adskilles de med kommaer.

3.1. Grundlæggende erklæring

def printWelcome = {println "Velkommen til lukninger!" }

Her, lukningen printVelkommen udskriver en erklæring, når den påberåbes. Lad os nu skrive et hurtigt eksempel på en unary lukning:

def print = {name -> println name}

Her, lukningen Print tager en parameter - navn - og udskriver det, når det påberåbes.

Da definitionen af ​​en lukning ligner en metode, lad os sammenligne dem:

def formatToLowerCase (navn) {return name.toLowerCase ()} def formatToLowerCaseClosure = {name -> return name.toLowerCase ()} 

Her opfører metoden og den tilsvarende lukning sig på samme måde. Der er dog subtile forskelle mellem en lukning og en metode, som vi diskuterer senere i afsnittet Lukninger vs metoder.

3.2. Udførelse

Vi kan udføre en lukning på to måder - vi kan påberåbe det som om det var en hvilken som helst anden metode, eller vi kan bruge opkald metode.

For eksempel som en almindelig metode:

print ("Hej! Lukning") formatToLowerCaseClosure ("Hej! Lukning") 

Og udføre med opkald metode:

print.call ("Hej! Lukning") formatToLowerCaseClosure.call ("Hej! Lukning")

4. Parametre

Parametrene for Groovy-lukninger svarer til parametrene for almindelige metoder.

4.1. Implicit parameter

Vi kan definere en unary lukning uden en parameter fordi når parametre ikke er defineret, antager Groovy en implicit parameter med navnet “det":

def greet = {return "Hello! $ {it}"} assert greet ("Alex") == "Hello! Alex"

4.2. Flere parametre

Her er en lukning, der tager to parametre og returnerer resultatet af at multiplicere dem:

def multiplicer = {x, y -> returner x * y} assert multiplicer (2, 4) == 8

4.3. Parametertyper

I eksemplerne hidtil har der ikke været nogen type leveret med vores parametre. Vi kan også indstille typen af ​​lukningsparametre. Lad os for eksempel omskrive formere sig metode til at overveje andre operationer:

def beregne = {int x, int y, String operation -> def result = 0 switch (operation) {case "ADD": result = x + y break case "SUB": result = xy break case "MUL": result = x * y break case "DIV": resultat = x / y break} returresultat} assert beregne (12, 4, "ADD") == 16 assert beregne (43, 8, "DIV") == 5.375

4.4. Varargs

Vi kan erklære et variabelt antal argumenter i lukninger svarende til almindelige metoder. For eksempel:

def addAll = {int ... args -> return args.sum ()} hæv addAll (12, 10, 14) == 36

5. En lukning som et argument

Vi kan passere en Lukning som et argument for en almindelig Groovy-metode. Dette gør det muligt for metoden at kalde vores lukning for at fuldføre sin opgave, så vi kan tilpasse dens adfærd.

Lad os diskutere en simpel brugssag: beregning af mængden af ​​almindelige tal.

I dette eksempel defineres lydstyrken som areal ganget med højde. Beregning af areal kan dog variere for forskellige former.

Derfor skriver vi bind metode, der lukker areaCalculator som et argument, og vi videregiver implementeringen af ​​områdeberegningen under påkaldelse:

def volume (Closure areaCalculator, int ... dimensions) {if (dimensions.size () == 3) {return areaCalculator (dimensions [0], dimensions [1]) * dimensions [2]} ellers if (dimensions.size () == 2) {return areaCalculator (dimensions [0]) * dimensions [1]} ellers hvis (dimensions.size () == 1) {return areaCalculator (dimensions [0]) * dimensions [0]}} hævder volumen ({l, b -> return l * b}, 12, 6, 10) == 720 

Lad os finde et volumen af ​​en kegle ved hjælp af samme metode:

hævde lydstyrke ({radius -> returner Math.PI * radius * radius / 3}, 5, 10) == Math.PI * 250

6. Indlejrede lukninger

Vi kan erklære og påberåbe lukninger inde i en lukning.

Lad os for eksempel tilføje en logningsevne til det allerede diskuterede Beregn lukning:

def beregne = {int x, int y, String operation -> def log = {println "Performing $ it"} def result = 0 switch (operation) {case "ADD": log ("Addition") result = x + y break case "SUB": log ("Subtraktion") resultat = xy break case "MUL": log ("Multiplikation") resultat = x * y break case "DIV": log ("Division") resultat = x / y break } returner resultat}

7. Lazy Evaluation of Strings

Groovy Snors evalueres og interpoleres normalt på tidspunktet for oprettelsen. For eksempel:

def name = "Samwell" def welcomeMsg = "Welcome! $ name" hævder welcomeMsg == "Welcome! Samwell"

Selv hvis vi ændrer værdien af navn variabel, den VelkommenMsg vil ikke ændre sig:

name = "Tarly" hævder velkommenMsg! = "Velkommen! Tarly"

Lukningsinterpolation giver os mulighed for at give doven evaluering af Snors, genberegnet ud fra de aktuelle værdier omkring dem. For eksempel:

def fullName = "Tarly Samson" def greetStr = "Hej! $ {-> fullName}" hævder greetStr == "Hej! Tarly Samson"

Kun denne gang påvirker ændring af variablen også den interpolerede strenges værdi:

fullName = "Jon Smith" hævder greetStr == "Hej! Jon Smith"

8. Lukninger i samlinger

Groovy Collections bruger lukninger i mange af deres API'er. Lad os for eksempel definere en liste over emner og udskrive dem ved hjælp af den unære lukning hver, som har en implicit parameter:

def list = [10, 11, 12, 13, 14, true, false, "BUNTHER"] liste. hver {println it} hævder [13, 14] == list.findAlle {det forekomst af heltal && it> = 13}

Ofte, baseret på et eller andet kriterium, kan det være nødvendigt at oprette en liste fra et kort. For eksempel:

def map = [1:10, 2:30, 4: 5] hævder [10, 60, 20] == map.collect {it.key * it.value} 

9. Lukninger vs metoder

Indtil videre har vi set syntaksen, udførelsen og parametrene for lukninger, som ligner nogenlunde metoder. Lad os nu sammenligne lukninger med metoder.

I modsætning til en almindelig Groovy-metode:

  • Vi kan passere en Lukning som et argument til en metode
  • Unære lukninger kan bruge det implicitte det parameter
  • Vi kan tildele en Lukning til en variabel og udføre den senere, enten som en metode eller med opkald
  • Groovy bestemmer tilbageløbstypen for lukningerne ved kørsel
  • Vi kan erklære og påberåbe lukninger inde i en lukning
  • Lukninger returnerer altid en værdi

Derfor har lukninger fordele i forhold til regelmæssige metoder og er et stærkt træk ved Groovy.

10. Konklusion

I denne artikel har vi set, hvordan man opretter lukninger i Groovy og undersøgt, hvordan de bruges.

Lukninger giver en effektiv måde at indsprøjte funktionalitet i objekter og metoder til forsinket udførelse.

Som altid er kode- og enhedstestene fra denne artikel tilgængelige på GitHub.