Currying er en funksjon som finnes i de fleste moderne programmeringsspråk. Den oversetter en enkelt funksjon med flere argumenter til en serie funksjoner hver med ett argument. Dette gjør det i hovedsak mulig å lagre funksjoner i variabler og skape funksjoner som returnerer funksjoner.
Selv om det kan virke som et merkelig konsept i begynnelsen, er det en kraftig teknikk som kan være svært nyttig til tider. I denne opplæringen skal jeg vise deg hvordan du kan dra nytte av funksjon currying i Swift.
Før du definerer våre egne tilpassede funksjoner, skal jeg først vise deg et enkelt eksempel på currying i Swift ved hjelp av klasser.
Åpne Xcode, opprett en ny iOS- eller OS X-lekeplass, og legg til følgende kode for det:
klasse car var hastighet = 0 func accelerateBy (faktor: Int) -> Int speed + = faktor returhastighet la car1 = Bil ()
Vi definerer en grunnklass med en egenskap og en forekomstsmetode eller -funksjon. Vi lager også en forekomst av klassen, akkumulatorer1
. Vi kan ringe til accelerateBy (_ :)
metode for vår Bil
eksempel med følgende kode:
car1.accelerateBy (10)
Det er imidlertid en annen måte å utføre denne metoden ved hjelp av funksjon currying. I eksempelet ovenfor kaller du metoden direkte på akkumulatorer1
til tross for at metoden faktisk er definert i Bil
klasse. Metoden vi har skrevet er ikke spesifikk for akkumulatorer1
eksempel, men snarere Bil
klasse. Når du ringer denne metoden, er det som virkelig skjer, at Swift først går til Bil
klasse, henter accelerateBy (_ :)
metode, forteller hvilken metode som brukes, og utfører deretter en endret metode som er spesifikk for den forekomsten. For å vise deg hvordan dette virker, legg til følgende linje på lekeplassen din:
Car.accelerateBy (akkumulatorer1)
Det vi gjør her er å få tilgang til accelerateBy (_ :)
metode av Bil
klasse og passerer, som en parameter, hvilken forekomst vi vil at denne funksjonen skal utføres på. I lekeplassens sidefelt kan du se at resultatet av denne metoden er en annen funksjon.
Hva er dette (Funksjon) Resultatet representerer er faktisk en ny accelerateBy (_ :)
metode spesifikk for akkumulatorer1
forekomst. Denne returnerte funksjonen er unik ved at den spesifikt refererer til akkumulatorer1
's hastighet
eiendom i stedet for generisk metode du definerte tidligere, som kan referere til hastighet
eiendom av noen Bil
forekomst.
Som du forventer, kan vi sende nye parametere til denne returnerte funksjonen for å utføre den som vi vanligvis gjør. Legg til følgende linje med kode til lekeplassen din:
Car.accelerateBy (akkumulatorer1) (10)
Med denne koden passerer vi 10
som en parameter i den unike accelerateBy (_ :)
metode og få akkumulatorer1
Nåværende hastighet returneres som et resultat.
Gratulerer! Du har nettopp utnyttet funksjon currying i Swift for aller første gang.
I tillegg til å currying sammen flere funksjoner, den Function Resultatet at koden din er tilbake kan også lagres i en variabel. Dette gjør at du kan lagre og raskt gjenbruke accelerateBy (_ :)
metode spesifikk for din akkumulatorer1
forekomst. Legg til følgende linjer på lekeplassen din:
la a = Car.accelerateBy (car1) a (10) a (20) a (30)
Du kan se den variabelen en
Nå oppfører seg som enhver annen globalt definert funksjon. Fordelen er at den er spesifikk for en bestemt Bil
eksempel, som kan defineres på kjøretid i stedet for kompileringstid. På lekeplassen kan du se de forventede utgangene som vises i sidefeltet.
Til slutt skal jeg vise deg hvordan du kan returnere en funksjon fra en annen funksjon ved å reimplementere oppførselen til Bil
klasse som vi nettopp har sett på. Vi skal gjøre dette ved å definere en funksjon som returnerer en annen funksjon. I koden din kan denne funksjonen se slik ut:
func someFunction (input: AnyObject) -> (AnyObject) -> AnyObject // Gjør ting for å returnere en funksjon
Vi definerer someFunction (_ :)
funksjon, som aksepterer en AnyObject
parameter og returnerer en annen funksjon som også aksepterer en AnyObject
parameter som returnerer en AnyObject
resultat. Denne typen funksjonsdefinisjon kan se veldig forvirrende og skremmende i starten. For å forenkle det kan vi dra nytte av typealias
søkeord i Swift for å kartlegge et nytt navn til en hvilken som helst datatype.
Legg til følgende kode på lekeplassen din:
type AI (Int) => Int> Funksjonalitet (Car)>> IntFunksjon Return Car.accelerateBy (bil) la newA = accelerationForCar (car1) newA (10)
Ved bruk av typealias
å kartlegge navnet på IntFunction
til (Int) -> Int
datatype, har vi sterkt forenklet accelerationForCar (_ :)
funksjonsdefinisjon. De (Int) -> Int
datatype representerer bare en funksjon som aksepterer en int
parameter og returnerer en int
verdi.
Denne nye funksjonen bruker den innebygde oppførselen til Bil
klasse for å returnere en IntFunction
objekt som kan lagres i en variabel og brukes som vi gjorde før.
Mens den innebygde funksjonen currying atferd i Swift er veldig nyttig, kan du ønske å lage dine egne funksjoner som ikke er relatert til klasser. For denne delen av opplæringen skal vi først bruke eksemplet på en funksjon som multipliserer et annet tall med en konstant verdi.
Tenk deg at du vil opprette en funksjon som aksepterer et enkelt inngangsnummer og multipliserer det med 5. Denne enkle funksjonen kan se slik ut:
func multiplyBy5 (a: Int) -> Int return a * 5
Forestill deg nå at du trenger en lignende funksjon, men du trenger den til å formere med 10 i stedet for 5. Da trenger du en annen funksjon til å formere med 20. Mens du kan lage tre lignende funksjoner og nevne dem multiplyBy5
, multiplyBy10
, og multiplyBy20
, dette kan håndteres mye bedre ved å bruke funksjon currying.
Legg til følgende kodestykke til lekeplassen din:
func multiplyBy (a: Int) -> IntFunction func nestedMultiply (b: Int) -> Int return a * b return nestedMultiply multiplyBy (10) (20) la multiplyBy5 = multiplyBy (5) multiplyBy5 (4)
Vi definerer multiplyBy (_ :)
funksjon som aksepterer en int
som den eneste parameteren og returnerer en funksjon av typen IntFunction
, Datatypen vi definerte tidligere i denne opplæringen. I denne funksjonen definerer vi en annen funksjon, nestedMultiply (_ :)
. Vi nest denne funksjonen innen den første slik at den ikke kan utføres utenfor omfanget av multiplyBy (_ :)
funksjon og har tilgang til en
inngangsparameter.
De tre linjene under funksjonsdefinisjonen er enkle eksempler på hvordan du kan curry funksjonene sammen.
Mens du kan lage funksjoner for currying ved hjelp av nestede funksjoner, kan du også opprette dem ved hjelp av nedleggelser eller ved å definere flere sett med parametere. For eksempel, legg til følgende kodestykke til lekeplassen din:
func add (a: Int) -> IntFunction return b i a + b la add2 = add (2) add2 (4) func subtrahere (a: Int) (b: Int) -> Int return b - a la subtract5 = subtrahere (5) subtrahere5 (b: 8)
Som du kan se, kan disse to nye funksjonene bli kurert sammen på samme måte som alle de andre funksjonene har vært gjennom hele denne opplæringen. Det eneste unntaket er at med funksjonen definert med to sett med parametere, må du eksplisitt kjenne den andre parameteren.
Det er ingen grense for antall nivåer av funksjon currying du kan implementere innenfor koden din. Følgende kode viser et eksempel på tre curried funksjoner og hvordan det adskiller seg over en enkelt funksjon med tre parametere.
func multiply (a: Int, b: Int, c: Int) -> Int return a * b * c func multipliserer (a: Int) -> (Int) -> IntFunction func nestedMultiply1 (b: Int) > IntFunction func nestedMultiply2 (c: Int) -> Int return a * b * c returner nestedMultiply2 retur nestedMultiply1 multiply (4, 5, 6) multiply (4) (5)
Hovedforskjellen mellom disse to multiplikasjonsfunksjonene er at den curried versjonen effektivt kan stoppes og lagres i en variabel etter at den første eller andre parameter har blitt behandlet. Dette gjør funksjonen veldig lett å gjenbruke og overføre som et objekt.
Funksjon currying i Swift er et vanskelig konsept å forstå, men i kjernen er det i utgangspunktet om to sentrale begreper:
Det finnes en rekke måter å curryfunksjoner sammen og, mens bare int
Datatype ble brukt i denne opplæringen, de samme prosessene kan brukes med hvilken som helst datatype i Swift-prosjektene. Dette gjør at funksjonene kan lagres i variabler og brukes mange ganger i hele koden.
Som alltid, vær så snill å legge igjen dine kommentarer og tilbakemelding nedenfor i kommentarene.