Samouczek Scala: Przykład i kod języka programowania Scala

Podsumowanie samouczka Scali

Ten tutorial scala omawia wszystkie aspekty i tematy scala. Nauczysz się od podstaw wszystkich podstaw, takich jak czym jest scala, proces instalacji scala, programy Scala, funkcje Scala, leniwa ocena, interfejs typów, klasy i obiekty, dziedziczenie, abstrakcje, Java i różnice w skalach itp.

Czym jest Scala?

Scala jest statycznie typowanym językiem programowania, który łączy w sobie zarówno programowanie funkcjonalne, jak i obiektowe, aby zwiększyć skalowalność aplikacji. Scala działa głównie na platformie JVM i może być również używana do pisania oprogramowania na natywne platformy przy użyciu Scala-Native i JAVASCRIPT środowiska uruchomieniowe poprzez ScalaJs.

Scala to skalowalny język używany do pisania oprogramowania na wiele platform. Stąd wzięła się nazwa „Scala”. Język ten ma na celu rozwiązywanie problemów Java jednocześnie będąc bardziej zwięzłym. Początkowo zaprojektowany przez Martina Odersky'ego, został wydany w 2003 roku.

Dlaczego warto uczyć się Scali

Oto główne powody, dla których warto uczyć się języka programowania Scala:

  • Scala jest łatwa do nauczenia dla programistów obiektowych, Java deweloperzy. W ostatnich latach staje się jednym z najpopularniejszych języków.
  • Scala oferuje użytkownikom najwyższej klasy funkcje
  • Scala może być wykonywana na FMV, torując w ten sposób drogę do interoperacyjności z innymi językami.
  • Jest przeznaczony dla aplikacji współbieżnych, rozproszonych i odpornych na działanie komunikatów. Jest to jeden z najbardziej wymagających języków tej dekady.
  • Jest to zwięzły, mocny język i może szybko rosnąć w zależności od potrzeb użytkowników.
  • Jest zorientowany obiektowo i ma wiele funkcjonalnych funkcji programistycznych, zapewniających programistom dużą elastyczność w zakresie kodowania w taki sposób, w jaki chcą.
  • Scala oferuje wiele typów kaczek
  • Ma mniej szablonów, jeśli pochodzisz Java
  • Frameworki Lift and Play napisane w Scali są w fazie wzrostu.

Jak zainstalować Scalę

Aby rozpocząć pisanie programów w języku Scala, musisz mieć go zainstalowany na swoim komputerze. Aby to zrobić, musisz odwiedzić ich witrynę https://www.scala-lang.org/download/ w celu pobrania najnowszej wersji Scali.

Po kliknięciu łącza zostaną nam wyświetlone dwie opcje, które możemy wybrać, aby zainstalować Scalę na naszych komputerach. W tym samouczku Scala pobierzemy IntelliJ IDEA.

Jak zainstalować Scalę

Po odwiedzeniu łącza pobierania znajdziesz dwie wersje IntelliJ IDE.

Na potrzeby tego samouczka dotyczącego języka Scala pobierzemy wersję Community Edition, która jest bezpłatna i zawiera wszystko, co potrzebne do pisania programów w języku Scala.

Jak zainstalować Scalę

Krok 1) Wybierz wersję Community
Na stronie kliknij menu rozwijane Community Edition.

Daje nam możliwość pobrania IntelliJ IDE razem z JBR, który zawiera implementację JDK (Java Development Kit) OpenJDK, którego Scala potrzebuje do skompilowania i uruchomienia kodu.

Jak zainstalować Scalę

Krok 2) Uruchom instalację
Po pobraniu programu IntelliJ kliknij go dwukrotnie, aby uruchomić kreatora instalacji, i postępuj zgodnie z instrukcjami.

Jak zainstalować Scalę

Krok 3) Wybierz lokalizację
Wybierz lokalizację, w której chcesz zainstalować IDE.

Jak zainstalować Scalę

Jeśli nie pobrałeś wersji z pakietem JDK, i tak pojawi się monit, w którym należy zaznaczyć pole wyboru, aby zaznaczyć opcję pobrania.

Jak zainstalować Scalę

Krok 4) Kliknij dalej
Pozostaw pozostałe ustawienia domyślne bez zmian i kliknij Dalej.

Jak zainstalować Scalę

Krok 5) Kliknij ikonę uruchamiania
Po zakończeniu instalacji uruchom IntelliJ IDE, klikając jego ikonę uruchamiania w menu startowym, jak zwykłą aplikację.

Jak zainstalować Scalę

Nadal musisz przejść dodatkowy etap dodania wtyczki Scala do IntelliJ; robisz to poprzez kliknięcie rozwijanego menu konfiguracji znajdującego się w prawym dolnym rogu ekranu i wybranie opcji wtyczki.

Jak zainstalować Scalę

Jak zainstalować Scalę

Na karcie Rynek, wyszukiwanie Scala wyświetli wtyczkę jako pierwszy wynik pod tagiem Języki.

Krok 6) Zainstaluj wtyczkę
Kliknij przycisk instaluj, co spowoduje rozpoczęcie pobierania wtyczki.

Jak zainstalować Scalę

Krok 7) Uruchom ponownie IDE
Po zakończeniu pobierania zostaniesz poproszony o ponowne uruchomienie IDE, aby zainstalowana wtyczka mogła zacząć działać.

Jak zainstalować Scalę

Po ponownym uruchomieniu znajdziesz się na tej samej stronie, co poprzednio, kiedy uruchamialiśmy IDE, ale tym razem zainstalowaliśmy już wtyczkę Scala.

Program Scala Hello World

Krok 1) Wybierz opcję Utwórz projekt, co przeniesie nas na stronę, na której możemy wybrać rodzaj języka, w jakim będzie używany nasz projekt.

Program Scala Hello World

Krok 2) wybierz Scalę zaznaczając pole wyboru Scala i kliknij Dalej.

Program Scala Hello World

Krok 3) Wybierz lokalizację, w której chcesz zapisać plik naszego projektu i nadaj naszemu projektowi nazwę.

Program Scala Hello World

Jeśli katalog nie istnieje, IntelliJ poprosi nas o pozwolenie na utworzenie folderu. Zaakceptuj i kliknij Zakończ. Zostaniesz przeniesiony do projektu Scala, który obecnie nie ma żadnego kodu Scala.

Załadowanie niektórych indeksów zajmie trochę czasu, więc nie martw się, jeśli nie możesz od razu nic zrobić, gdy na dole IDE znajduje się pasek postępu. Oznacza to po prostu, że IDE ładuje niektóre pliki niezbędne do uruchomienia Scali i pomoc w autouzupełnianiu IDE.

Krok 4) Następnie klikniemy kartę projektów po lewej stronie IDE i rozwiniemy ją, abyśmy mogli zobaczyć zawartość naszego projektu.

Program Scala Hello World

W tej chwili projekt jest pusty i zawiera jedynie folder .idea i plik hello-world.iml wygenerowany przez IDE. Nas interesuje folder src. Src to miejsce, w którym przechowujemy kod źródłowy naszego projektu. Tutaj utworzymy nasz pierwszy plik Scala.

Krok 5) Kliknij prawym przyciskiem myszy src, aby otworzyć menu umożliwiające utworzenie nowego pliku Scala.

Utwórz nowy plik Scala

Następnie utworzymy nazwę pliku. W tym samouczku dotyczącym Scali użyjemy słowa hello, a następnie z listy rozwijanej wybierzemy, co umieścić jako zawartość pliku Scala. Wybierz „Obiekt”

Program Scala Hello World

Gdy to zrobimy, będziemy mieli plik Scala zawierający obiekt Singleton, którego użyjemy do uruchomienia naszego kodu.

Program Scala Hello World

Teraz, gdy masz plik Scala z obiektem Hello. Swój pierwszy program napiszesz rozszerzając utworzony obiekt za pomocą słowa kluczowego App.

Rozszerzając nasz obiekt o aplikację, powiedz kompilatorowi, który kod ma zostać uruchomiony podczas uruchamiania programu. Natychmiast po rozszerzeniu aplikacji po lewej stronie pojawi się zielona strzałka wskazująca, że ​​możesz teraz uruchomić swój program.

Program Scala Hello World

Program Scala Hello World

Wewnątrz obiektu Hello piszemy jedną funkcję println(), która służy do wypisywania znajdującego się w nim tekstu na konsoli. Uruchomimy nasz kod klikając na zieloną strzałkę.

Kliknięcie strzałki powoduje wyświetlenie opcji Uruchom, witaj, po kliknięciu nasz kod zacznie się kompilować i po kilku sekundach zobaczymy wyniki działania naszego programu wydrukowane z konsoli wbudowanej w IntelliJ IDE.

Program Scala Hello World

I gotowe, pomyślnie zainstalowaliśmy Scalę i uruchomiliśmy nasz pierwszy program.

Co możesz zrobić ze Scalą

  • Tworzenie frontendowych stron internetowych w ScalaJS
  • Rozwój mobilny, oba Android Rozwój i IOS – z Scala Native
  • Biblioteki po stronie serwera, takie jak HTTP4S, Akka-Http, Play Framework
  • Korzystanie z Internetu rzeczy
  • Produkcja gier
  • NLP – przetwarzanie języka naturalnego z wykorzystaniem pakietu bibliotek ScalaNLP
  • Testowanie zaawansowanych technik programowania, takich jak programowanie funkcyjne i programowanie obiektowe
  • Zbuduj wysoce współbieżną aplikację komunikacyjną, korzystając z aktorów i biblioteki dla JVM inspirowanej Erlangiem
  • Użyj go do uczenia maszynowego przy użyciu bibliotek takich jak Figaro, które programuje probabilistycznie i Apache Spark że

Funkcje anonimowe

Język Scala ma funkcje anonimowe, które są również nazywane literały funkcyjne. Scala jako język funkcjonalny często oznacza, że ​​programiści dzielą duże problemy na wiele małych zadań i tworzą wiele funkcji w celu rozwiązania tych problemów. Aby ułatwić tworzenie funkcji, Scala zawiera te funkcje, które można utworzone bez nazwy. Możemy je przypisać bezpośrednio do zmiennych lub definicji „def”, jak pokazano na poniższym przykładzie w Scali:

val multiplyByTwo = (n:Int) => n * 2
def multiplyByThree = (n:Int) => n *3

Następnie możemy używać funkcji w zwykły sposób, przekazując im parametry.

multiplyByTwo(3)

//6

multiplyByThree(4)

//12

Metody te przydadzą się, gdy chcemy mieć czysty i zwięzły kod. Funkcji anonimowych możemy używać przy definiowaniu metod, które nie są duże i nie wymagają dużej ilości kodu w swojej treści. Są bardzo proste i nie wymagają ceremonii przy ich tworzeniu.

Metody te nie ograniczają się do funkcji z argumentami i można ich używać do tworzenia instancji metod, które nie przyjmują żadnych argumentów.

val sayHello = ()=>{ println("hello") }

Większość tych anonimowych funkcji jest używana w innych częściach naszego kodu, w których musimy utworzyć szybką funkcję.

Innym powodem, dla którego te funkcje są również określane jako funkcje wbudowane. Korzystanie z funkcji anonimowych to powszechny wzorzec powszechnie używany w bibliotece kolekcji do wykonywania szybkich działań na kolekcji.

Na przykład mamy metodę filter, która wykorzystuje funkcję wbudowaną/funkcję anonimową, aby utworzyć kolejną kolekcję zawierającą tylko elementy spełniające kryteria zdefiniowane przez nas w funkcji anonimowej.

val myList = List(1,2,3,4,5,6,7)

val myEvenList = myList.filter((n: Int) => n % 2 == 0)
//List(2,4,6)

val myOddList = myList.filter((n:Int) => n % 2 != 0)
//List(1,3,5,7)

Tutaj metody, które mamy jako funkcje anonimowe, to te, które sprawdzają, czy wartość, którą otrzymujemy z listy, są nieparzyste i parzyste, i zwracają element.

//the one checking that the value is even
(n: Int) => n % 2 == 0

//the one checking that the value is odd
(n:Int) => n % 2 != 0

W Scali można także używać symboli wieloznacznych tam, gdzie nie ma nazwy parametrów naszej funkcji anonimowej. Na przykład

var timesTwo = (_:Int)*2

timesTwo(5)
//10

W tym scenariuszu nie nazywamy parametru, który przekazujemy. Jedyne, co reprezentujemy, to podkreślenie.

Leniwa ocena

Większość języków ocenia zmienne i parametry funkcji sekwencyjnie, jeden po drugim. W Scali mamy słowo kluczowe o nazwie lazy, które pomaga w radzeniu sobie z wartościami, do których nie chcemy być oceniani, dopóki się do nich nie odwołamy.

Zmienna oznaczona jako leniwa nie będzie oceniana w miejscu, w którym została zdefiniowana. Jest to powszechnie znane jako ocenianie chętne. Zmienna będzie oceniana dopiero w momencie odwołania się do niej w dalszej części kodu.

Może to być pomocne, gdy ocena wartości może być kosztownym obliczeniem. Jeśli nie jest tak, że wartość jest zawsze potrzebna, możemy uniknąć wykonywania kosztownych obliczeń, które mogą spowolnić nasze oprogramowanie poprzez spowolnienie naszej zmiennej.

lazy val myExpensiveValue = expensiveComputation

def runMethod()={
    if(settings == true){
        use(myExpensiveValue)
    }else{
        use(otherValue)
    }
}

Nie jest to jedyny przypadek użycia leniwych zmiennych. Pomagają także w rozwiązywaniu problemów związanych z zależnością cykliczną w kodzie.

W przypadku, gdy ustawienia są fałszywe, być może nie będziemy musieli używać myExpensiveValue, co może pomóc nam uniknąć wykonywania kosztownych obliczeń, co pomaga zapewnić użytkownikom dobrą zabawę podczas korzystania z naszej aplikacji, ponieważ nasze inne potrzeby mogą zostać poprawnie obliczone bez przytłaczania pamięć RAM.

W przypadku, gdy ustawienia są fałszywe, być może nie będziemy musieli używać myExpensiveValue, co może pomóc nam uniknąć wykonywania kosztownych obliczeń, co pomaga zapewnić użytkownikom dobrą zabawę podczas korzystania z naszej aplikacji, ponieważ nasze inne potrzeby mogą zostać odpowiednio obliczone bez przytłaczania pamięć RAM.

Lenistwo pomaga również w przypadku argumentów funkcji, gdzie argumenty są używane tylko wtedy, gdy istnieje odwołanie do nich wewnątrz funkcji. Ta koncepcja nazywa się parametrami Call-by-name.

def sometimesUsedString(someValue:String, defaultValue:=> String)={
 if(someValue != null){
   use(defaultValue)
 }else{
   use(someValue)
   }
 }

Wiele języków używa metody call-by-value do oceny argumentów. Parametr przekazywany przez call-by-name będzie oceniany tylko wtedy, gdy będzie potrzebny w ciele funkcji i nie będzie oceniany przedtem. Po ocenie wartości jest ona przechowywana i może być ponownie użyta później bez konieczności jej ponownej oceny. Koncepcja ta jest znana jako memoizacja.

Wpisz wnioskowanie

W Scali nie musisz deklarować typów dla każdej tworzonej zmiennej. Dzieje się tak, ponieważ kompilator Scala może wnioskować o typach w oparciu o ocenę prawej strony. Dzięki temu Twój kod będzie bardziej zwięzły – uwalnia nas od pisania szablonów, w których oczekiwany typ jest oczywisty

var first:String = "Hello, "
var second:String = "World"
var third = first + second
//the compile infers that third is of type String

Funkcja wyższego rzędu

Funkcja wyższego rzędu to funkcja, która może przyjmować funkcje jako argumenty i zwracać funkcję jako typ zwracany. W Scali funkcje są uważane za obywateli pierwszej kategorii. Korzystanie z tych funkcji w ten sposób pozwala nam na dużą elastyczność w zakresie rodzaju programów, które możemy tworzyć. Możemy tworzyć funkcje dynamicznie i dynamicznie przekazywać funkcjonalność innym funkcjom.

def doMathToInt(n:Int, myMathFunction:Int=>Int): Int ={
    myMathFunction(n)
}

W powyższej funkcji przekazujemy int oraz funkcję, która przyjmuje int i zwraca int. Możemy przekazać dowolną funkcję tego podpisu. Przez sygnaturę rozumiemy wejście i wyjście funkcji. Sygnatura Int=>Int oznacza, że ​​funkcja przyjmuje Int jako dane wejściowe i zwraca Int jako dane wyjściowe.

Podpis ()=>Int oznacza, że ​​funkcja nie przyjmuje niczego na wejściu i zwraca Int na wyjściu. Przykładem takiej funkcji może być funkcja generująca dla nas losową liczbę int.

def generateRandomInt()={
 return scala.util.Random.nextInt()
}

Powyższa funkcja posiada sygnaturę ()=>Int

Możemy mieć funkcję, która ma sygnaturę scala ()=>Unit. Oznacza to, że funkcje nie pobierają niczego i nie zwracają typu. Funkcja może polegać na wykonywaniu pewnego rodzaju obliczeń poprzez zmianę czegoś na wykonanie czegoś z góry określonego.

Tego rodzaju metody nie są jednak mile widziane, ponieważ wydają się być czarną skrzynką, która może wpływać na system w nieznany sposób. Są również nietestowalne. Posiadanie jawnych typów danych wejściowych i wyjściowych pozwala nam wnioskować o tym, co robi nasza funkcja.

Funkcja wyższego rzędu może również zwracać funkcję.

Na przykład moglibyśmy stworzyć metodę, która utworzy funkcję potęgującą, tj. pobierze liczbę i zastosuje do niej potęgę.

def powerByFunction(n:Int):Int=>Int = {
  return (x:Int)=> scala.math.pow(x,n).toInt
}

Powyższa funkcja przyjmuje liczbę typu int. Nasz typ zwracany to anonimowa funkcja, która przyjmuje Int x, * używamy int x jako argumentu funkcji potęgowej.

Curry

W Scali możemy przekształcić funkcję przyjmującą dwa argumenty w funkcję przyjmującą po jednym argumencie. Kiedy przekazujemy jeden argument, częściowo go stosujemy i otrzymujemy funkcję, która do zakończenia funkcji przyjmuje jeden argument. Curry umożliwia nam tworzenie funkcji poprzez częściowe dodanie niektórych argumentów.

Może to być przydatne do dynamicznego tworzenia funkcji, zanim będziemy mieli pełny zestaw argumentów

def multiply two numbers(n:Int)(m:Int): Unit ={
  return n * m
}

Jeśli musimy utworzyć funkcję mnożącą przez określoną liczbę, nie musimy tworzyć kolejnej metody mnożenia.

Możemy po prostu wywołać funkcję .curried w naszej funkcji powyżej i uzyskać funkcję, która najpierw przyjmuje jeden argument i zwraca częściowo zastosowaną funkcję

def multiplyTwoNumbers(n:Int)(m:Int): Unit ={
  return n * m
}

var multiplyByFive = multiplyTwoNumbers(5) 

multiplyByFive(4)

//returns 20

Dopasowywanie wzorców

Scala ma wbudowany potężny mechanizm pomagający nam sprawdzić, czy zmienna spełnia określone kryteria, podobnie jak zrobilibyśmy to w instrukcji switch w Java lub w serii instrukcji if/else. Język posiada funkcję dopasowywania wzorców, za pomocą której możemy sprawdzić, czy zmienna jest określonego typu. Dopasowywanie wzorców w Scali jest potężne i można go wykorzystać do zniszczenia komponentów wyposażonych w metodę unapply w celu uzyskania interesujących nas pól bezpośrednio z dopasowywanej zmiennej.

Dopasowywanie wzorców w Scali zapewnia również przyjemniejszą składnię w porównaniu z instrukcją switch.

myItem match {
  case true => //do something
  case false => //do something else
  case  _ => //if none of the above do this by default
}

Porównujemy naszą zmienną z zestawem opcji i kiedy dopasowywana zmienna spełnia kryteria, wyrażenie po prawej stronie grubej strzałki (=>) jest oceniane i zwracane jako wynik dopasowania.

Używamy podkreślenia, aby wychwycić przypadki, które nie są dopasowane w naszym kodzie. Odzwierciedla zachowanie domyślnego przypadku w przypadku instrukcji switch.

class Animal(var legs:Int,var sound:String)
class Furniture(var legs:Int, var color:Int, var woodType:String)

myItem match {
case myItem:Animal => //do something
case myItem:Furniture => //do something else
case _ => //case we have a type we don't recognize do sth else
}

W powyższym kodzie możesz znaleźć typ zmiennej myItem i na tej podstawie przejść do określonego kodu.

Dopasowanie wzorca sprawdza, czy zmienna pasuje

Podkreślenie działa jako symbol zastępczy pasujący do dowolnego innego warunku, który nie jest spełniony przez inne elementy w powyższych instrukcjach case. Bierzemy zmienną myItem i wywołujemy metodę dopasowania.

  • sprawdzamy, czy myItem jest prawdziwy, używając i wykonując pewne czynności logiczne po prawej stronie grubej strzałki „=>”.
  • używamy podkreślenia, aby dopasować wszystko, co nie pasuje do żadnej instrukcji case, którą zdefiniowaliśmy w kodzie.

Dzięki klasom Case możemy nawet pójść dalej i zniszczyć klasę, aby uzyskać pola wewnątrz obiektu.

Używając słowa kluczowego seal do definiowania naszych klas, uzyskujemy korzyść polegającą na tym, że kompilator dokładnie sprawdza przypadki, z którymi staramy się dopasować, i ostrzega nas, jeśli zapomnimy zająć się konkretnym.

Niezmienność

Za pomocą słowa kluczowego val można tworzyć wartości, których nie mogą zmieniać inne funkcje w Scali. Osiąga się to w Java za pomocą słowa kluczowego final. W Scali robimy to, używając słowa kluczowego val podczas tworzenia zmiennej, zamiast używać var, czyli alternatywy, której użylibyśmy do utworzenia zmiennej modyfikowalnej.

Zmienna zdefiniowana za pomocą słowa kluczowego val jest tylko do odczytu, natomiast zmienna zdefiniowana za pomocą var może zostać odczytana i zmieniona przez inne funkcje lub dowolnie przez użytkownika w kodzie.

var changeableVariable = 8

changeableVariable =10
//the compiler doesn't complain, and the code compiles successfully

println(changeableVariable)
//10

val myNumber = 7

myNumber = 4

//if we try this the code won't compile

Próba przypisania wartości do myNumber po zadeklarowaniu jej jako wartości val powoduje błąd kompilacji lub „ponowne przypisanie do wartości val”.

Po co używać niezmienności?

Niezmienność pomaga nam zapobiegać nieoczekiwanym zmianom naszych wartości przez kod i innych programistów, co mogłoby prowadzić do nieoczekiwanych wyników, jeśli zamiast tego mają używać przechowywanej przez nas wartości, mogą zamiast tego utworzyć jej kopię. W ten sposób zapobiega się błędom, które mogą być spowodowane przez wielu aktorów zmieniających tę samą zmienną.

Klasy i przedmioty

Wszyscy wiemy, że obiekty to byty świata rzeczywistego, a klasa to szablon definiujący obiekty. Klasy mają zarówno stan, jak i zachowania. Stany są albo wartościami, albo zmiennymi. Zachowania są metodami w Scali.

Przyjrzyjmy się, jak zdefiniować klasę, utworzyć jej instancję i używać jej w języku Scala.

Tutaj klasa o nazwie Rectangle, która ma dwie zmienne i dwie funkcje. Możesz także użyć parametrów lib bezpośrednio jako pól w programie. Masz obiekt, który ma metodę główną i utworzył instancję klasy z dwiema wartościami.

Przykład:

class Rectangle( l: Int,  b: Int) {
  val length: Int = l
  val breadth: Int = b
  def getArea: Int = l * b
  override def toString = s"This is rectangle with length as $length and breadth as  $breadth"
  }
object RectObject {
  def main(args: Array[String]) {
    val rect = new Rectangle(4, 5)
    println(rect.toString)
    println(rect.getArea)    
  }
}

Wszystkie pola i metody są domyślnie publiczne w Scali. Konieczne jest użycie override, ponieważ metoda toString jest zdefiniowana dla obiektu w Scali.

Dziedzictwo

W języku Scala występuje wiele typów dziedziczenia (takich jak dziedziczenie pojedyncze, wielopoziomowe, wielokrotne, hierarchiczne i hybrydowe), które mają wiele wspólnego z tradycyjnymi formami występującymi w Java. Można dziedziczyć zarówno z klas, jak i cech. Możesz dziedziczyć elementy jednej klasy do innej klasy, używając słowa kluczowego „rozszerza”. Umożliwia to ponowne użycie.

Możliwe jest dziedziczenie z jednej klasy lub wielu klas. Możliwe jest także dziedziczenie z podklas, które same mają swoje nadklasy, tworząc przy tym hierarchię dziedziczenia.

W poniższym przykładzie w Scali klasą bazową jest Circle, a klasą pochodną jest Sphere. Okrąg ma wartość zwaną promieniem, która jest dziedziczona w klasie Sphere. Metoda calcArea jest zastępowana przy użyciu słowa kluczowego override.

Przykład:

class Circle {
  val radius = 5;
  def calcArea = {
    println(radius * radius )
  }
}
class Sphere extends Circle{
 override def calcArea = {
    println(radius * radius * radius )
  }
}
  object SphereObject{
    def main(args : Array[String]){
      new Sphere().calcArea 
    }
  }

Abstrakcja

W Scali możemy tworzyć abstrakcyjne metody i pola składowe, korzystając z abstrakcyjnych klas i cech. Wewnątrz abstrakcyjnych klas i cech możemy definiować abstrakcyjne pola bez konieczności ich implementowania.

Przykład:

trait MakesSound{
    var nameOfSound:String
    def sound():String
}
abstract class HasLegs(var legs:Int){
    val creatureName:String

    def printLegs():String={
        return s"$creatureName has this number of legs: $legs"
    }
}

Te pola są implementowane przez klasy rozszerzające cechę lub klasę abstrakcyjną. Możesz użyć cech, aby tworzyć kontrakty dotyczące tego, co nasza aplikacja powinna być w stanie zrobić, a następnie implementować te metody później.

trait DatabaseService{
    def addItemName(itemName:String)
    def removeItem(itemId:Int)
    def updateItem(itemId:Int, newItemName:String)
}

W ten sposób możemy zaplanować, jak będzie wyglądać nasza aplikacja, bez konieczności wdrażania metod, które pomogą nam wyobrazić sobie, jak będą wyglądać różne metody. Wynika to ze wzorca znanego jako programowanie abstrakcji, a nie faktyczna implementacja.

Klasa poprzedzona słowem kluczowym streszczenie może zawierać zarówno metody abstrakcyjne, jak i nieabstrakcyjne. Jednak wielokrotne dziedziczenie nie jest obsługiwane w klasie abstrakcyjnej. Można więc rozszerzyć maksymalnie jedną klasę abstrakcyjną.

Obiekty Singletona

Singleton to klasa, której instancja jest tworzona tylko raz w programie. Pochodzi z popularnego i użytecznego wzorca programowania znanego jako „wzorzec singletonowy”. Jest to przydatne przy tworzeniu instancji, które mają być długotrwałe i będą powszechnie dostępne w całym programie, a których stan jest integralną częścią koordynowania zdarzeń w systemie. Tworzenie takiej klasy w Scali jest łatwe, ponieważ Scala zapewnia nam prosty sposób tworzenia singletonów za pomocą słowa kluczowego object.

object UserProfile{
    var userName=""
    var isLoggedIn:Boolean = false
}

Możemy następnie odwoływać się do tego obiektu w całym programie, mając gwarancję, że wszystkie części naszego programu zobaczą te same dane, ponieważ istnieje tylko jedna jego instancja.

def getLoggedInStatus():Boolean={
   return UserProfile.isLoggedIn
}

def changeLoggedInStatus():Boolean={
    UserProfile.isLoggedIn = !UserProfile.isLoggedIn
    return  UserProfile.isLoggedIn
}

W Scali nie ma koncepcji elementów statycznych, dlatego należy używać obiektów singletonowych, które zachowują się jak statyczne elementy klasy.

Klasy niejawne

Klasy niejawne to nowa funkcjonalność dodana po wersji 2.1. Jej głównym zadaniem jest dodanie nowej funkcjonalności do klas zamkniętych.

Niejawne słowo kluczowe powinno być zdefiniowane w klasie, obiekcie lub cesze. Główny konstruktor klasy ukrytej powinien mieć dokładnie jeden argument na swojej pierwszej liście parametrów. Może również zawierać dodatkową niejawną listę parametrów.

W poniższym przykładzie Scala dodano nową funkcję zastępowania samogłosek ciągu znaków *.

object StringUtil {
  implicit class StringEnhancer(str: String) {
    
    def replaceVowelWithStar: String = str.replaceAll("[aeiou]", "*")
  }
}

Musisz zaimportować w klasie, w której go używasz.

import StringUtil.StringEnhancer

object ImplicitEx extends App {
  val msg = "This is Guru99!"
  println(msg.replaceVowelWithStar)
}

Programowanie obiektowe (OOP) a programowanie funkcjonalne (FP)

W programach OOP konstruuje się je poprzez grupowanie danych i funkcji, które operują na tych danych, w wysoce połączone jednostki. Obiekty przenoszą swoje dane w polach i metodach, które na nich operują. W tym stylu programowania główną abstrakcją są dane, ponieważ tworzone metody mają operować na danych.

Programowanie funkcjonalne, z drugiej strony, oddziela dane i funkcje, które na nich operują. Dzięki temu programiści mogą traktować funkcje jako abstrakcję i siłę napędową podczas modelowania programów.

Scala umożliwia programowanie funkcyjne poprzez traktowanie funkcji jako obywateli pierwszej klasy, co pozwala na przekazywanie ich jako wartości do innych funkcji i zwracanie ich również jako wartości. Połączenie tych dwóch paradygmatów uczyniło Scalę doskonałym wyborem do tworzenia złożonego oprogramowania w różnych branżach, takich jak Data Science.

Ważne frameworki w Scali

Oto kilka ważnych frameworków Scali

  • Graj to platforma aplikacji internetowych o otwartym kodzie źródłowym, która wykorzystuje Architektura MVC. Wydany w 2007 roku i obecnie licencjonowany na platformie Apache, stał się najpopularniejszym frameworkiem w GitHub w 2013 roku. Firmy takie jak LinkedIn, Walmart, Samsung, Eero korzystają z tego frameworka.
  • Wyciąg to kolejny darmowy framework sieciowy napisany w Scali, uruchomiony w 2007 roku. Foursquare wykorzystuje framework Lift. Jest wydajny i szybszy w budowie.
  • Jak
  • koty
  • Spark

Wsparcie współbieżności

  • Wartości w Scali są domyślnie niezmienne. To sprawia, że ​​bardzo dobrze dostosowuje się do współbieżnego środowiska.
  • W Scali jest wiele funkcji, które sprawiają, że najlepiej sprawdza się w przypadku aplikacji współbieżnych.
  • Futures i Promises ułatwiają asynchroniczne przetwarzanie danych, wspierając w ten sposób paralelizm.
  • Akka – narzędzie wykorzystujące model współbieżności Actor. Istnieje pewna liczba aktorów, którzy podejmują działania po otrzymaniu wiadomości.
  • Współbieżność przy użyciu wątków z Java może być również obsługiwany w Scali.
  • Przetwarzanie strumieniowe to kolejna świetna funkcja, która umożliwia ciągłe przetwarzanie danych w czasie rzeczywistym.

Scala ma jedne z najlepszych bibliotek współbieżności na rynku Java ekosystem.

  • Tubylec Java threads
  • Włókna z bibliotek takich jak Vertex
  • ZIO – biblioteka zawierająca prymitywy ułatwiające radzenie sobie z obliczeniami współbieżnymi i asynchronicznymi
  • STM – transakcja
  • Future – wbudowany w język Scala

Java kontra Scala

Oto główne różnica między Java i Scalę.

Scala Java
Bardziej zwarty i zwięzły Stosunkowo większe fragmenty kodu
Zaprojektowany i opracowany jako język zorientowany obiektowo i funkcjonalnie.
Obsługuje szeroką gamę funkcjonalnych funkcji programowania, takich jak współbieżność, niezmienność.
Pierwotnie rozwijany jako język obiektowy i zaczął obsługiwać funkcje programowania funkcyjnego w ostatnich dniach. Nadal nie jest silny jako język programowania funkcyjnego.
Wykorzystuje model aktora do obsługi współbieżności, który jest nowoczesny Używa konwencjonalnego modelu opartego na wątkach do współbieżności.
Obsługuje frameworki – Play, Lift Obsługuje Spring, Grails i wiele więcej
Obsługuje leniwą ocenę Nie obsługuje leniwej oceny
Brak elementów statycznych Zawiera elementy statyczne
Obsługuje przeciążanie operatora Nie obsługuje przeciążania operatora
Kompilacja kodu źródłowego jest stosunkowo powolna Kompilacja kodu źródłowego jest szybsza niż w Scali
Cechy – zachowuj się jak Java 8 interfejsy Java 8 interfejsów próbuje wypełnić lukę pomiędzy klasami i interfejsami
Konieczne jest przepisanie Przepisywanie nie jest wymagane
Brak gwarancji, że kody są wolne od błędów Pełna gwarancja mniejszych usterek
Obsługuje kompatybilność wsteczną. Scala nie obsługuje kompatybilności wstecznej.
Operatory są traktowane inaczej Java i nie są wywołaniami metod. Wszyscy operatorzy na wpisach korzystają z metody wywoływanej w Scali.
Obsługuje wielokrotne dziedziczenie przy użyciu klas, ale nie klas abstrakcyjnych Nie obsługuje wielokrotnego dziedziczenia przy użyciu klas, ale przez interfejsy
Kod jest napisany w zwartej formie. Kod jest napisany w długiej formie.
Scala nie zawiera słowa kluczowego static. Java zawiera słowo kluczowe static.

Podsumowanie

W tym samouczku nauczyłeś się, jak rozpocząć pracę ze Scalą. Poznałeś także cechy funkcjonalne i obiektowe. Odkryłeś także podobieństwa i różnice między nimi Java i Scalę. Ten samouczek powinien był ci pomóc dzięki szerokiej gamie dobrze zademonstrowanych przykładów.