Scala — pierwsze kroki cz.2

Poniższy wpis jest kontynuacją części pierwszej kursu.

Krok trzeci - definiowanie funkcji

Do definiowania funkcji lub metody służy słowo kluczowe def.
Napiszemy funkcję max zwracającą większą wartość z dwóch wartości przekazanych jako parametry:

reklama

def max(x:Int, y:Int):Int = {
      if(x > y) x
      else y
}

max jest nazwą funkcji przyjmującej dwa parametry typu całkowitego - Int i zwracającą również typ Int. Jak widać pominięto znane z innych języków słowo kluczowe return. Jest ono opcjonalne w tym przypadku i moglibyśmy je dopisać przed x i y. Zwracana jest zawsze ostatnia wartość z miejsca do którego doszła funkcja.

Nie potrzeba też średników po każdej instrukcji. Kompilator sam znajduje gdzie się ona kończy. Charakterystyczne też jest odwrócenie kolejności nazwy argumentu z jego typem, jak również pojawienie się zwracanego typu po liście parametrów funkcji. (Może niektórzy już zorientowali się, że przypomina to sposób zapisu z języka UML.). Nawiasy klamrowe tak jak w większości języków pochodzących od C definiują nam zasięg. W tym przypadku ciało funkcji. Znak równości w pierwszej linii mówi, że funkcja zwraca wartość. Jest ona obowiązkowa dla funkcji. Jeśli jej nie napiszemy to oznacza to procedurę i brak zwracania wartości (oznacza to zwracanie Unit - coś podobnego do void w C).

Funkcję możemy wywołać np. w taki sposób:

max(3, 5)

Na co interpreter odpowie w znany nam już sposób:

res0: Int = 5

Dla małych funkcji i metod możemy skrócić zapis do jednej linijki. Nasza funkcja max może być zapisana w następujący sposób:

def max(x:Int, y:Int) = if(x > y) x else y

Podobnie jak przy definicji z inicjalizacją zmiennych funkcja potrafi sama odgadnąć zwracany typ.
Gdy napiszemy procedurę kompilator przypisze jej zwracany typ jako Unit:

def powitanie() = println("Witaj świecie!")
powitanie: ()Unit

Krok czwarty - piszemy skrypty

Mimo, że Scala powstała do pisania dużych programów i systemów to umożliwiono pisanie w niej skryptów. Stwórzmy plik o nazwie hello.scala i napiszmy w nim następującą treść:

println("Witaj świecie z wnętrza skryptu!")

Skrypt uruchamiamy poleceniem:

scala hello.scala

Uruchomienie skryptu trwa kilka sekund ze względu na czas kompilacji. Skrypty w Scali wydają się być miłym dodatkiem i mogą okazać się czasami użyteczne. Jednak nie zastąpią wielu przypadkach ani skryptów Pythona, ani też nie zastąpią większych programów pisanych w Scali. Pobieranie parametrów z konsoli po uruchomieniu skryptu odbywa się za pomocą listy argumentów args z numerem argumentu wpisanym w okrągłe nawiasy. Aby to sprawdzić podmieniamy zawartość skryptu na:

println("Witaj " + args(0) + "!")

Przy okazji widzimy, że napisy skleja się podobnie do C i Java.
Teraz uruchamiamy poleceniem:

scala hello.scala Janie

Jeśli zapomnimy wpisać argumentu to pojawi się błąd i rzucony zostanie wyjątek, ponieważ próbujemy dostać się do pustej listy argumentów. Zamieńmy kod na poniższy:

if(!args.isEmpty) println("Witaj " + args(0) + "!")
else println("Witaj Anonimie!")

Dzięki sprawdzeniu czy lista nie jest pusta unikamy problemów.

W systemach Uniksowych możemy uruchamiać skrypty podając tylko ich nazwę, ale dopisując w pierwszej linii za pomocą czego ma on być uruchomiony. W Ubuntu po instalacji Scali z pakietów będzie to:

#!/usr/bin/scala
!#

Po nadaniu praw do uruchomienia plikowi możemy uruchomić skrypt poleceniem:

./hello.scala

Krok piąty - pętla while i zwrotnica if

Wygląd pętli while jest dość standardowy. Napiszmy funkcję liczącą silnie z wykorzystaniem pętli while:

def silnia(n:Int) = {
    var i = 1
    var s = 1
    while( i < n) {
        i += 1
        s *= i 
    } 
    s 
}

silnia(5)

Nie jest to kod pokazujący typowy styl programowania w Scali ponieważ, nie unikamy tutaj iterowania po indeksie i co jest zbędne. W kodzie znajdziemy też znane z języka C i Javy skróty operacji: i += 1 to i = i + 1 oraz s *= i to s = s * i.

Umieśćmy teraz w pliku drukujargumenty.scala następujący kod:


var i = 0
while (i < args.length) {
    if(i != 0) print(" ")
    print(args(i))
    i += 1
}
println()

i uruchamiamy poleceniem:

scala drukujargumenty.scala Scala jest fajna

Instrukcja if sprawdza warunek logiczny i podobnie jak w Javie nie przepuści innej operacji nie zwracającej prawdy lub fałszu. Instrukcje w bloku if muszą być ograniczone nawiasami klamrowymi gdy jest ich więcej.
Funkcja print drukuje napis na konsolę bez dodawania znaku nowej linii, a metoda length listy args sprawdza ilość elementów w liście (w tym przypadku ilość argumentów w konsoli).
Jeśli chcemy napisać kilka poleceń w jednej linii to możemy oddzielić je średnikami.

Krok szósty - pętla for i foreach

Realizacja funkcji silni za pomocą pętli for:

def silnia(n:Int) = {
    var s = 1
    for(i <- 1 to n) { s *= i }
    s
}

silnia(5)

Jak widać nie jest to typowa dla języków C i Javy funkcja for. Bardziej podobna jest do pętli z Pythona. Generuje liczby od 1 do n ( 1 to n) i podstawia pod zmienną i.
Drukowanie argumentów z konsoli w pliku drukujargumenty.scala można skrócić do:

for(arg <- args) print(arg + " ")
println()

Foreach jest metodą którą posiadają kolekcje (sekwencje, listy, tablice itp.). Umożliwia ona pisanie kodu w zwarty sposób. Naszą funkcję silnia możemy napisać dzięki temu krócej:

def silnia(n:Int) = {
    var s = 1
    (1 to n).foreach(i => s *= i)
    s
}
silnia(5)

We wnętrzu metody foreach użyta została funkcja anonimowa. Jest to skrócona forma, która mogłaby wyglądać tak:

(i:Int) => {s *= i}


Do pełnej funkcji brakuje słowa kluczowego def, nazwy funkcji i zamiast znaku równości mamy =>.

W pliku drukujargumenty.scala możemy podmienić kod na:

args.foreach(arg => print(arg + " "))
println()

Minusem jest fakt, że na końcu zostanie spacja. Można to rozwiązać jeszcze prościej używając metody mkString:

print(args.mkString(" "))

Użycie metody foreach pokazuje styl programowania funkcyjnego.

Do zobaczenia w następnym odcinku ;)

 

programowanie

Komentarze