Õppige Scalat 0–60: põhitõed

Scala on üldotstarbeline, kõrgel tasemel programmeerimiskeel, mis pakub tasakaalu funktsionaalsete ja objektorienteeritud programmide arendamise vahel.

Mis on funktsionaalne programmeerimine? Lihtsamalt öeldes on funktsioonid funktsionaalse programmeerimise esmaklassilised kodanikud. Programmi põhifunktsioonide laiendamiseks kipume kirjutama täiendavaid klasse, mis laienevad teatud juhistele / liidestele. Funktsionaalses programmeerimises aitavad funktsioonid meil sama saavutada.

Kõigi selgituste jaoks kasutame Scala REPL-i. See on väga mugav ja informatiivne vahend Scala õppimiseks. See logib armasad väikesed sõnumid selle kohta, kuidas meie koodi tõlgendatakse ja täidetakse.

Alustame kõigepealt põhitõdedest.

1. Muutujad

Muutumatuid muutujaid saab määratleda, kasutades val:

scala> val name = "King"name: String = King

Muutuvaid muutujaid saab määratleda ja muuta, kasutades järgmist var:

scala> var name = "King"name: String = King
scala> name = "Arthur"name: String = Arthur

Me defmäärame muutumatu väärtuse sildi, mille hindamine lükatakse hilisemaks ajaks edasi. See tähendab, et märgistuse väärtust hinnatakse iga kord laisasti.

scala> var name = "King"name: String = King
scala> def alias = namealias: String
scala> aliasres2: String = King

Kas jälgisite midagi huvitavat?

Määratlemisel aliasei omistatud väärtust, alias: Stringkuna see on laisalt seotud, kui me seda kutsume. Mis juhtuks, kui muudaksime väärtust name?

scala> aliasres5: String = King
scala> name = "Arthur, King Arthur"name: String = Arthur, King Arthur
scala> aliasres6: String = Arthur, King Arthur

2. Kontrollige voolu

Otsustusloogika väljendamiseks kasutame juhtimisvoogude avaldusi.

Võite kirjutada if-elseavalduse järgmiselt:

if(name.contains("Arthur")) { print("Entombed sword")} else { print("You're not entitled to this sword")}

Või võite kasutada järgmist while:

var attempts = 0while (attempts < 3) { drawSword() attempts += 1}

3. Kogud

Scala eristab selgesõnaliselt muutumatuid ja muudetavaid kogusid - otse paketi nimeruumist endast ( scala.collection.immutablevõi scala.collection.mutable).

Erinevalt muutumatutest kogudest saab muutuvaid kogusid oma asukohas värskendada või laiendada. See võimaldab meil kõrvalmõjuna elemente muuta, lisada või eemaldada.

Kuid muutumatute kogude liitmis-, eemaldamis- või värskendustoimingute tegemine tagastab selle asemel uue kogu.

Muutumatud kogud imporditakse alati automaatselt domeeni scala._ (mis sisaldab ka varjunime scala.collection.immutable.List) kaudu.

Muutuvate kogude kasutamiseks peate siiski selgesõnaliselt importima scala.collection.mutable.List.

Funktsionaalse programmeerimise vaimus lähtume eeskätt keele muutumatutest aspektidest, tehes väikseid kõrvalepõikeid muutlikule küljele.

Nimekiri

Saame loendi luua mitmel viisil:

scala> val names = List("Arthur", "Uther", "Mordred", "Vortigern")
names: List[String] = List(Arthur, Uther, Mordred, Vortigern)

Teine mugav lähenemisviis on loendi määratlemine miinusoperaatori abil ::. See ühendab peaelemendi loendi järelejäänud sabaga.

scala> val name = "Arthur" :: "Uther" :: "Mordred" :: "Vortigern" :: Nil
name: List[String] = List(Arthur, Uther, Mordred, Vortigern)

Mis on samaväärne järgmisega:

scala> val name = "Arthur" :: ("Uther" :: ("Mordred" :: ("Vortigern" :: Nil)))
name: List[String] = List(Arthur, Uther, Mordred, Vortigern)

Loendielementidele pääseme juurde otse nende registri järgi. Pidage meeles, et Scala kasutab nullipõhist indekseerimist:

scala> name(2)
res7: String = Mordred

Mõned levinumad abimeetodid on järgmised:

list.head, mis tagastab esimese elemendi:

scala> name.head
res8: String = Arthur

list.tail, mis tagastab loendi saba (mis sisaldab kõike, välja arvatud pea):

scala> name.tail
res9: List[String] = List(Uther, Mordred, Vortigern)

Määra

Setvõimaldab meil luua kordumatute üksuste rühma. Listei kaota duplikaate vaikimisi.

scala> val nameswithDuplicates = List("Arthur", "Uther", "Mordred", "Vortigern", "Arthur", "Uther")
nameswithDuplicates: List[String] = List(Arthur, Uther, Mordred, Vortigern, Arthur, Uther)

Siin korratakse "Arthurit" kaks korda ja sama ka "Utherit".

Loome samade nimedega komplekti. Pange tähele, kuidas see duplikaadid välistab.

scala> val uniqueNames = Set("Arthur", "Uther", "Mordred", "Vortigern", "Arthur", "Uther")
uniqueNames: scala.collection.immutable.Set[String] = Set(Arthur, Uther, Mordred, Vortigern)

Konkreetse elemendi olemasolu saab kontrollida komplektis, kasutades järgmist contains():

scala> uniqueNames.contains("Vortigern")res0: Boolean = true

Elemente saab komplekti lisada meetodi + abil (milleks on vaja varargsmuutuva pikkusega argumente)

scala> uniqueNames + ("Igraine", "Elsa", "Guenevere")res0: scala.collection.immutable.Set[String] = Set(Arthur, Elsa, Vortigern, Guenevere, Mordred, Igraine, Uther)

Samamoodi saame -meetodi abil elemente eemaldada

scala> uniqueNames - "Elsa"
res1: scala.collection.immutable.Set[String] = Set(Arthur, Uther, Mordred, Vortigern)

Kaart

Mapon korduv kogu, mis sisaldab vastendamist keyelementidest vastavate valueelementideni, mida saab luua järgmiselt:

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)

Kaardi konkreetse võtme väärtustele pääseb juurde järgmiselt:

scala> kingSpouses("Vortigern")res0: String = Elsa

Kaardile saab lisada kirje järgmise +meetodi abil:

scala> kingSpouses + ("Launcelot" -> "Elaine")res0: scala.collection.immutable.Map[String,String] = Map(King Uther -> Igraine, Vortigern -> Elsa, King Arthur -> Guenevere, Launcelot -> Elaine)

Olemasoleva kaardistamise muutmiseks lisame värskendatud võtmeväärtuse lihtsalt uuesti:

scala> kingSpouses + ("Launcelot" -> "Guenevere")res1: scala.collection.immutable.Map[String,String] = Map(King Uther -> Igraine, Vortigern -> Elsa, King Arthur -> Guenevere, Launcelot -> Guenevere)

Pange tähele, et kuna kogu on muutumatu, tagastab iga redigeerimistoiming rakendatud muudatustega uue kogu ( res0, res1). Algne kollektsioon kingSpousesjääb muutumatuks.

4. Funktsionaalsed kombinatorid

Nüüd, kui oleme õppinud üksuste komplekti rühmitama, vaatame, kuidas saaksime funktsionaalsete kombinatorite abil sellistes kogudes sisukaid teisendusi genereerida.

John Hughesi lihtsate sõnadega:

Kombinaator on funktsioon, mis ehitab programmi fragmentidest programmi fragmente.

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.

  1. 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
  • Mõned põhitõed erinevate kollektsioonide kohta
  • Ülevaade funktsionaalsete kombinaatorite kasutamisest kollektsioonides

Loodan, et see artikkel oli teile kasulik. Esmalt järgitakse artiklite seerias Scala õppimist.

Teises osas õpime tundide, tunnuste, kapseldamise ja muude objektorienteeritud mõistete määratlemist.

Palun andke mulle teada oma tagasisidest ja ettepanekutest, kuidas sisu parandada. Seni ❤ kodeerimine.