Lær Scala fra 0–60: Det grunnleggende

Scala er et generelt programmeringsspråk på høyt nivå som gir en balanse mellom å utvikle funksjonelle og objektorienterte programmer.
Hva handler funksjonell programmering om? Enkelt sagt er funksjoner førsteklasses borgere i funksjonell programmering. For å utvide et kjernesett av funksjoner i et program, har vi en tendens til å skrive flere klasser som strekker seg over visse retningslinjer / grensesnitt. I funksjonell programmering hjelper funksjoner oss med å oppnå det samme.
Vi bruker Scala REPL for alle forklaringer. Det er et veldig nyttig og informativt verktøy for å lære Scala. Den logger søte små meldinger om hvordan koden vår blir tolket og utført.
La oss starte med det grunnleggende først.
1. Variabler
Vi kan definere uforanderlige variabler ved hjelp av val
:
scala> val name = "King"name: String = King
Muterbare variabler kan defineres og modifiseres ved hjelp av var
:
scala> var name = "King"name: String = King
scala> name = "Arthur"name: String = Arthur
Vi bruker def
til å tilordne en etikett til en uforanderlig verdi hvis evaluering blir utsatt til et senere tidspunkt. Det betyr at etikettens verdi blir lat evaluert hver gang etter bruk.
scala> var name = "King"name: String = King
scala> def alias = namealias: String
scala> aliasres2: String = King
Så du noe interessant?
Mens vi definerte alias
, ble det ikke tildelt noen verdi alias: String
siden den er lat assosiert når vi påkaller den. Hva ville skje hvis vi endrer verdien på name
?
scala> aliasres5: String = King
scala> name = "Arthur, King Arthur"name: String = Arthur, King Arthur
scala> aliasres6: String = Arthur, King Arthur
2. Kontroll flyt
Vi bruker uttalelser om kontrollflyt for å uttrykke beslutningslogikken vår.
Du kan skrive en if-else
uttalelse som nedenfor:
if(name.contains("Arthur")) { print("Entombed sword")} else { print("You're not entitled to this sword")}
Eller du kan bruke while
:
var attempts = 0while (attempts < 3) { drawSword() attempts += 1}
3. Samlinger
Scala skiller eksplisitt mellom uforanderlige versus foranderlige samlinger - rett fra selve pakkenavnområdet ( scala.collection.immutable
eller scala.collection.mutable
).
I motsetning til uforanderlige samlinger kan foranderlige samlinger oppdateres eller utvides på plass. Dette gjør at vi kan endre, legge til eller fjerne elementer som en bivirkning.
Men å utføre tillegg, fjerning eller oppdatering av uforanderlige samlinger returnerer en ny samling i stedet.
Uforanderlige samlinger importeres alltid automatisk via scala._
(som også inneholder alias for scala.collection.immutable.List
).
Imidlertid, for å bruke mutable samlinger, må du eksplisitt importere scala.collection.mutable.List
.
I ånden av funksjonell programmering vil vi først og fremst basere eksemplene våre på uforanderlige aspekter av språket, med mindre omveier inn i den foranderlige siden.
Liste
Vi kan lage en liste på forskjellige måter:
scala> val names = List("Arthur", "Uther", "Mordred", "Vortigern")
names: List[String] = List(Arthur, Uther, Mordred, Vortigern)
En annen praktisk tilnærming er å definere en liste ved hjelp av ulempeoperatøren ::
. Dette forbinder et hodeelement med den gjenværende halen på en liste.
scala> val name = "Arthur" :: "Uther" :: "Mordred" :: "Vortigern" :: Nil
name: List[String] = List(Arthur, Uther, Mordred, Vortigern)
Som tilsvarer:
scala> val name = "Arthur" :: ("Uther" :: ("Mordred" :: ("Vortigern" :: Nil)))
name: List[String] = List(Arthur, Uther, Mordred, Vortigern)
Vi kan få tilgang til listeelementer direkte ved indeksen. Husk Scala bruker nullbasert indeksering:
scala> name(2)
res7: String = Mordred
Noen vanlige hjelpermetoder inkluderer:
list.head
, som returnerer det første elementet:
scala> name.head
res8: String = Arthur
list.tail
, som returnerer halen på en liste (som inkluderer alt unntatt hodet):
scala> name.tail
res9: List[String] = List(Uther, Mordred, Vortigern)
Sett
Set
tillater oss å opprette en ikke-gjentatt gruppe av enheter. List
eliminerer ikke duplikater som standard.
scala> val nameswithDuplicates = List("Arthur", "Uther", "Mordred", "Vortigern", "Arthur", "Uther")
nameswithDuplicates: List[String] = List(Arthur, Uther, Mordred, Vortigern, Arthur, Uther)
Her gjentas 'Arthur' to ganger, og det samme er 'Uther'.
La oss lage et sett med samme navn. Legg merke til hvordan det utelukker duplikatene.
scala> val uniqueNames = Set("Arthur", "Uther", "Mordred", "Vortigern", "Arthur", "Uther")
uniqueNames: scala.collection.immutable.Set[String] = Set(Arthur, Uther, Mordred, Vortigern)
Vi kan sjekke for eksistensen av spesifikt element i sett ved hjelp av contains()
:
scala> uniqueNames.contains("Vortigern")res0: Boolean = true
Vi kan legge til elementer i et sett ved hjelp av + -metoden (som tar varargs
f.eks. Argumenter med variabel lengde)
scala> uniqueNames + ("Igraine", "Elsa", "Guenevere")res0: scala.collection.immutable.Set[String] = Set(Arthur, Elsa, Vortigern, Guenevere, Mordred, Igraine, Uther)
På samme måte kan vi fjerne elementer ved hjelp av -
metoden
scala> uniqueNames - "Elsa"
res1: scala.collection.immutable.Set[String] = Set(Arthur, Uther, Mordred, Vortigern)
Kart
Map
er en iterabel samling som inneholder kartlegginger fra key
elementer til respektive value
elementer, som kan opprettes som:
scala> val kingSpouses = Map( | "King Uther" -> "Igraine", | "Vortigern" -> "Elsa", | "King Arthur" -> "Guenevere" | )
kingSpouses: scala.collection.immutable.Map[String,String] = Map(King Uther -> Igraine, Vortigern -> Elsa, King Arthur -> Guenevere)
Verdier for en bestemt nøkkel i kartet kan nås som:
scala> kingSpouses("Vortigern")res0: String = Elsa
Vi kan legge til en oppføring i Map ved hjelp av +
metoden:
scala> kingSpouses + ("Launcelot" -> "Elaine")res0: scala.collection.immutable.Map[String,String] = Map(King Uther -> Igraine, Vortigern -> Elsa, King Arthur -> Guenevere, Launcelot -> Elaine)
For å endre en eksisterende kartlegging legger vi bare til den oppdaterte nøkkelverdien på nytt:
scala> kingSpouses + ("Launcelot" -> "Guenevere")res1: scala.collection.immutable.Map[String,String] = Map(King Uther -> Igraine, Vortigern -> Elsa, King Arthur -> Guenevere, Launcelot -> Guenevere)
Merk at siden samlingen er uforanderlig, returnerer hver redigeringsoperasjon en ny samling ( res0
, res1
) med endringene som er brukt. Den originale samlingen kingSpouses
forblir uendret.
4. Funksjonelle kombinatorer
Nå som vi har lært hvordan vi grupperer et sett av enheter sammen, la oss se hvordan vi kan bruke funksjonelle kombinatorer til å generere meningsfulle transformasjoner på slike samlinger.
I John Hughes 'enkle ord:
En kombinator er en funksjon som bygger programfragmenter fra programfragmenter.An in-depth look at how combinators work is outside of this article’s scope. But, we’ll try to touch upon a high-level understanding of the concept anyhow.
Let’s take an example.
Suppose we want to find names of all queens using the kingSpouses
collection map that we created.
We’d want to do something along the lines of examining each entry in the map. If the key
has the name of a king, then we’re interested in the name of it’s spouse (i.e. queen).
We shall use the filter
combinator on map, which has a signature like:
collection.filter( /* a filter condition method which returns true on matching map entries */)
Overall we shall perform the following steps to find queens:
- Find the (key, value) pairs with kings’ names as keys.
- Extract the values (names of queen) only for such tuples.
The filter
is a function which, when given a (key, value), returns true / false.
- Find the map entries pertaining to kings.
Let’s define our filtering predicate function. Since key_value
is a tuple of (key, value), we extract the key using ._1
(and guess what ._2
returns?)
scala> def isKingly(key_value: (String, String)): Boolean = key_value._1.toLowerCase.contains("king")
isKingly: (key_value: (String, String))Boolean
Now we shall use the filter function defined above to filter
kingly entries.
scala> val kingsAndQueens = kingSpouses.filter(isKingly)
kingsAndQueens: scala.collection.immutable.Map[String,String] = Map(King Uther -> Igraine, King Arthur -> Guenevere)
2. Extract the names of respective queens from the filtered tuples.
scala> kingsAndQueens.values
res10: Iterable[String] = MapLike.DefaultValuesIterable(Igraine, Guenevere)
Let’s print out the names of queens using the foreach
combinator:
scala> kingsAndQueens.values.foreach(println)IgraineGuenevere
Some other useful combinators are foreach
, filter
, zip
, partition
, find
.
We shall re-visit some of these after having learnt how to define functions and passing functions as arguments to other functions in higher-order functions.
Let’s recap on what we’ve learned:
- Different ways of defining variables
- Various control-flow statements
- Noen grunnleggende om ulike samlinger
- Oversikt over bruk av funksjonelle kombinatorer på samlinger
Jeg håper du fant denne artikkelen nyttig. Det er først i en serie artikler å følge om å lære Scala.
I del to vil vi lære om å definere klasser, egenskaper, innkapsling og andre objektorienterte konsepter.
Gi meg gjerne beskjed om tilbakemeldinger og forslag til hvordan jeg kan forbedre innholdet. Inntil da, ❤ koding.