de Durga Prasana

Aflați Scala de la 0 la 60: noțiunile de bază

Aflati Scala de la 0 la 60 notiunile de baza
Fotografie de Sebastian Grochowicz pe Unsplash

Scala este un limbaj de programare de nivel general, cu scop general, care oferă un echilibru între dezvoltarea de programe funcționale și orientate obiect.

Ce este programarea funcțională? În termeni simpli, funcțiile sunt cetățenii de primă clasă în programarea funcțională. Pentru a extinde un set de funcționalități de bază ale unui program, avem tendința de a scrie clase suplimentare care se extind pe anumite linii directoare / interfețe. În programarea funcțională, funcțiile ne ajută să obținem același lucru.

Vom folosi Scala REPL pentru toate explicațiile. Este un instrument foarte util și informativ pentru învățarea Scala. Înregistrează mesaje mici drăguțe despre modul în care codul nostru este interpretat și executat.

Să începem mai întâi cu elementele de bază.

1. Variabile

Putem defini variabile imuabile folosind val:

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

Variabilele mutabile pot fi definite și modificate folosind var:

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

Folosim def pentru a atribui o etichetă unei valori imuabile a cărei evaluare este amânată pentru o dată ulterioară. Înseamnă că valoarea etichetei este evaluată leneș de fiecare dată la utilizare.

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

Ai observat ceva interesant?

În timp ce definea alias, nu a fost atribuită nicio valoare alias: String întrucât este leneș asociat, când îl invocăm. Ce s-ar întâmpla dacă schimbăm valoarea name?

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

2. Controlul fluxului

Folosim instrucțiuni de flux de control pentru a ne exprima logica decizională.

Puteți scrie un if-else declarație după cum urmează:

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

Sau, puteți utiliza while:

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

3. Colecții

Scala distinge în mod explicit între colecții imuabile și mutabile – chiar din spațiul de nume al pachetului în sine ( scala.collection.immutable sau scala.collection.mutable).

Spre deosebire de colecțiile imuabile, colecțiile mutabile pot fi actualizate sau extinse în loc. Acest lucru ne permite să schimbăm, adăugăm sau eliminăm elemente ca efect secundar.

Dar efectuarea operațiunilor de adăugare, eliminare sau actualizare a colecțiilor imuabile returnează o nouă colecție.

Colecțiile imuabile sunt întotdeauna importate automat prin scala._ (care conține și alias pentru scala.collection.immutable.List).

Cu toate acestea, pentru a utiliza colecții modificabile, trebuie să importați în mod explicit scala.collection.mutable.List.

În spiritul programării funcționale, ne vom baza în primul rând exemplele pe aspecte imuabile ale limbajului, cu ocoliri minore în partea mutabilă.

Listă

Putem crea o listă în diferite moduri:

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

O altă abordare utilă este definirea unei liste folosind contra :: operator. Aceasta unește un element de cap cu coada rămasă a unei liste.

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

Ceea ce este echivalent cu:

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

Putem accesa elementele listei direct prin indexul lor. Nu uitați că Scala folosește indexarea bazată pe zero:

scala> name(2)
res7: String = Mordred

Unele metode obișnuite de asistență includ:

list.head, care returnează primul element:

scala> name.head
res8: String = Arthur

list.tail, care returnează coada unei liste (care include totul, cu excepția capului):

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

A stabilit

Set ne permite să creăm un grup de entități care nu se repetă. List nu elimină duplicatele în mod implicit.

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

Aici, „Arthur” se repetă de două ori, la fel și „Uther”.

Să creăm un set cu aceleași nume. Observați cum exclude duplicatele.

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

Putem verifica existența unui element specific în Set folosind contains():

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

Putem adăuga elemente la un set folosind metoda + (care necesită varargs adică argumente cu lungime variabilă)

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

În mod similar, putem elimina elemente folosind - metodă

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

Hartă

Map este o colecție iterabilă care conține mapări din key elemente la respectiv value elemente, care pot fi create ca:

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)

Valorile pentru o anumită cheie din hartă pot fi accesate ca:

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

Putem adăuga o intrare pe hartă folosind + metodă:

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

Pentru a modifica o mapare existentă, pur și simplu adăugăm din nou valoarea-cheie actualizată:

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

Rețineți că, din moment ce colecția este imuabilă, fiecare operație de editare returnează o nouă colecție ( res0, res1) cu modificările aplicate. Colecția originală kingSpouses ramane neschimbat.

4. Combinatoare funcționale

Acum că am învățat cum să grupăm un set de entități împreună, să vedem cum putem folosi combinatori funcționali pentru a genera transformări semnificative pe astfel de colecții.

În cuvintele simple ale lui John Hughes:

Un combinator este o funcție care creează fragmente de program din fragmente de program.

O privire aprofundată asupra modului în care funcționează combinatorii este în afara domeniului de aplicare al acestui articol. Dar, vom încerca să abordăm oricum o înțelegere la nivel înalt a conceptului.

Să luăm un exemplu.

Să presupunem că vrem să găsim numele tuturor reginelor folosind kingSpouses harta de colectare pe care am creat-o.

Am vrea să facem ceva în conformitate cu examinarea fiecărei intrări de pe hartă. Dacă key are numele unui rege, apoi ne interesează numele soțului (adică regină).

Vom folosi filter combinator pe hartă, care are o semnătură ca:

collection.filter( /* a filter condition method which returns true on matching map entries */)

În general, vom efectua următorii pași pentru a găsi regine:

  • Găsiți perechile (cheie, valoare) cu numele regilor ca chei.
  • Extrageți valorile (numele reginei) numai pentru astfel de tupluri.

filter este o funcție care, atunci când este dată o (cheie, valoare), returnează adevărat / fals.

  1. Găsiți intrările pe hartă referitoare la regi.

Să definim funcția noastră de predicat de filtrare. De cand key_value este un tuplu de (cheie, valoare), extragem cheia folosind ._1 (si ghici ce ._2 se intoarce?)

scala> def isKingly(key_value: (String, String)): Boolean = key_value._1.toLowerCase.contains("king")
isKingly: (key_value: (String, String))Boolean

Acum vom folosi funcția de filtrare definită mai sus la filter intrări regale.

scala> val kingsAndQueens = kingSpouses.filter(isKingly)
kingsAndQueens: scala.collection.immutable.Map[String,String] = Map(King Uther -> Igraine, King Arthur -> Guenevere)

2. Extrageți numele reginelor respective din tuplurile filtrate.

scala> kingsAndQueens.values
res10: Iterable[String] = MapLike.DefaultValuesIterable(Igraine, Guenevere)

Să imprimăm numele reginelor folosind foreach combinator:

scala> kingsAndQueens.values.foreach(println)IgraineGuenevere

Unele alte combinații utile sunt foreach, filter, zip, partition, find.

Vom vizita din nou unele dintre acestea după ce am învățat cum să definim funcțiile și să trecem funcțiile ca argumente către alte funcții în funcții de ordin superior.

Să recapitulăm ceea ce am învățat:

  • Moduri diferite de definire a variabilelor
  • Diverse instrucțiuni de control-flux
  • Câteva elemente de bază despre diverse colecții
  • Prezentare generală a utilizării combinatorilor funcționali pe colecții

Sper că ți s-a părut util acest articol. Este primul dintr-o serie de articole de urmat despre învățarea Scalei.

În partea a doua, vom învăța despre definirea claselor, trăsăturilor, încapsularea și alte concepte orientate obiect.

Vă rugăm să nu ezitați să-mi spuneți feedback-ul și sugestiile dvs. despre cum pot îmbunătăți conținutul. Până atunci, ❤ codificare.