Ruby on Rails Studiehandbok Block, Procs och Lambdas

Ruby är ett språk med en uppsättning kraftfulla funktioner - den mest kraftfulla som förmodligen är Blocks, Procs och Lambdas. Kort sagt, med dessa funktioner kan du skicka kod till en metod och genomföra den koden vid en senare tidpunkt. Trots att de regelbundet använder dessa funktioner förstår de flesta utvecklare inte helt de subtila skillnaderna mellan dem.

Studiehandböcker: När du ansöker om ett programmeringsjobb kommer du ofta att presenteras med en frågesport som avser att bestämma din nivå av kunskap och erfarenhet inom ett visst ämne. De olika artiklarna i denna serie ger kondenserade lösningar på de frågor som du kan förvänta dig att se på sådana tester.

Blocks

Ett block är kod som implicit överförs till en metod genom användning av antingen krökta hängslen, ..., eller gör ... slut syntax. Det är vanlig konvention att använda ... för enstaka rader, och gör ... slut för flera linjeblock. Till exempel är följande block funktionellt desamma:

array = [1,2,3,4] array.map! gör | n | n * n slutet => [1, 4, 9, 16] array = [1,2,3,4] array.map! | n | n * n => [1, 4, 9, 16]

Den magiska bakom ett block är avkastning nyckelord; det försvinner genomförandet av anropsmetoden för att utvärdera blocket. Resultatet av blocket, om någon, utvärderas sedan av någon återstående kod i metoden. De avkastning uttalandet kan också acceptera parametrar, vilka sedan skickas in och utvärderas inom blocket. Tycker detta tillsammans, ett enkelt exempel på Karta! ovanstående metod skulle vara följande:

klass Array def karta! self.each_with_index do | värde, index | själv [index] = utbyte (värde) slutet änden

Denna enkla representation av Karta! kallar each_with_index metod och ersätter föremålet vid det angivna indexet med resultatet av blocket. Även om detta är ett triviellt exempel på blockanvändning, hjälper det att visa avkastnings makt. Användningen av block i Ruby är oändlig, och vi använder dem ofta i vår kod.


Procs

Ovanstående exempel visar en mindre begränsning av block: de är syntax och engångs. Vi måste skriva tillbaka block varje gång vi återanvända dem på olika arrays, men vi kan lagra ett block för senare användning genom att använda Ruby Proc Object. Vi kan lagra en Proc i en variabel och sedan uttryckligen vidarebefordra den till en metod som accepterar ett kallbart objekt. Omskrivning av ovanstående exempel som ett Proc skulle se ut som följande:

number_squared = Proc.new | n | n * n

Låt oss ändra vår Karta! metod för att acceptera och ringa Proc-objektet:

klass Array def map! (proc_object) self.each_with_index do | värde, index | self [index] = proc_object.call (värde) slutet änden array = [1,2,3,4] array.map! (number_squared) => [1, 4, 9, 16]

Observera att vi inte längre använder avkastning nyckelord; istället använder vi direkt ring upp metod på Proc-objektet, som överför värdet från matrisen. Vi får samma resultat som tidigare, men vi lagrar vårt block i en variabel för att återanvända en senare tidpunkt.


lambdas

Lambda-funktionen är nästan identisk med Procs men med två viktiga skillnader. Först kontrollerar en lambda antalet argumenter som den mottar och returnerar en Argument om de inte matchar. Till exempel:

l = lambda "I'm a lambda" l.call => "Jag är en lambda" l.call ('arg') ArgumentError: fel antal argument (1 för 0)

För det andra, lambdas ger en mindre avkastning - vilket innebär att när en Proc möter en avkastning i sin exekvering, stoppar den metoden och returnerar det angivna värdet. Lambdas å andra sidan, returnera deras värde till metoden, så att det kan fortsätta:

def proc_math Proc.new return 1 + 1 .call return 2 + 2 slutet def lambda_math lambda return 1 + 1 .call return 2 + 2 end proc_math # => 2 lambda_math # => 4

Som du kan se proc_math träffar returräkningen i Proc och returnerar värdet på 2. I kontrast, lambda_math hoppar tillbaka avkastningen och utvärderar 2 + 2 istället.

En sista anmärkning: Ruby 1.9 introducerar den nya "stabby" lambda-syntaxen (representerad av ->), som är funktionellt identisk med den traditionella lambda-syntaxen, men syntbyxen "stabby" är mycket renare.


Slutsats

I den här studieguiden har vi täckt de viktigaste skillnaderna mellan Block, Procs och Lambdas:

  • Block är engångsbruk.
  • Procs existerar som föremål.
  • Lambdas har strikt argumentkontroll.

För en mer djupgående recension rekommenderar jag följande resurser:

  • Rails Studiehandböcker här på Nettuts+
  • Ruby Proc Documentation
  • Programmerings Ruby 1.9
  • Metaprogramming Ruby: Program som Ruby Pros