Scala i Maven – część II
W ostatniej części udało się nam stworzyć projekt który świetnie będzie się nadawał do naszych testów jak również zdążyliśmy poznać podstawowe komendy służące do pracy z projektem. Podstawową zaletą naszego rozwiązania jest kompaktowość. W chwili obecnej możemy wybrać czy chcemy na nim pracować w oparciu o Netbeans’a, Eclipse czy choć by Textmate’a.
W tej części chcę przedstawić podstawowe zasady obowiązujące podczas użytkowania interpretera Scali w trybie interaktywnym, jak również podstawy samego języka. Pierwszą rzeczą o której musimy pamiętać to fakt że Scala jest językiem z dwóch światów, programowania obiektowego jak również funkcyjnego. Szczególną uwagę powinniśmy poświęcić na podejście funkcyjne, które stoi u podstaw tego języka, dla którego właściwie sam język powstał.
Podstawową zaletą Scali w procesie jej poznawania że praktycznie od samego początku będziemy mogli zacząć jej adopcje w naszych projektach gdyż możemy jej używać jak zwykłej Javy (oczywiście po uwzględnieniu różnic składni) tak aby z czasem, powiększając nasz zakres wiedzy, przejść do możliwości funkcyjnych, których siłę poznamy przy okazji Wielowątkowości która znacząco się różni od tej którą znamy z Javy.
Czas przejść do czynów, w tym celu uruchamiamy konsole scali za pomocą wcześniej poznanej komendy:
mvn scala:console
W tym momencie powinniśmy po zakończeniu wywołania zobaczyć taki oto komunikat oraz znak gotowości mówiący nam że możemy rozpocząć pracę z konsolą Scali:
Welcome to Scala version 2.7.3.RC2 (Java HotSpot(TM) 64-Bit Server VM, Java ...
Type in expressions to have them evaluated.
Type :help for more information.
scala> _
W tym momencie możemy rozpocząć pracę ze Scalą w trybie interaktywnym. Pierwszym naszym zadaniem będzie zdefiniowanie zmiennej:
scala> val helloWorld = "Hello world!"
helloWorld: java.lang.String = Hello world!
scala> helloWorld = "Second message"
:5: error: reassignment to val
helloWorld = "Second message"
^
Powinniśmy w tym momencie zwrócić uwage na to że nie użyliśmy ; na końcu lini gdyż w przeciwieństwie do Javy jest on opcjonalny w Scali. W drugim poleceniu chcieliśmy nadpisać wartość naszej zmiennej, nie udało się nam gdyż słowo kluczowe val mówi nam że zmienna ta jest typu immutable, (z punktu widzenia Javy - final) która zresztą stoi u podstaw programowanie funkcyjnego.
W przypadku programowania czysto obiektowego może być ciężko pracować na zmiennych val dlatego możemy użyć var:
scala> var muthelloWorld = "Hello world!"
muthelloWorld: java.lang.String = Hello world!
scala> muthelloWorld = "Second message"
muthelloWorld: java.lang.String = Second message
Jak widzimy wszystko działa zgodnie z naszymi oczekiwaniami. Warto przy tej okazji zwrócić uwagę na to że interpreter informuje nas w trybie interaktywnym o typie zmiennej. Jako że Scala jest językiem ścisłego typowania należy tutaj słowo wyjaśnienia, a mianowicie fakt że Scala podobnie jak C# w ver. 3.0 potrafi samemu odgadywać typ zmiennej na podstawie prawej strony przypisania. Poniżej ten sam przykład z definicją typu:
scala> var muthelloWorld:String = "Hello world!"
muthelloWorld: String = Hello world!
Również tutaj musimy wyjaśnić pewną nieścisłość, w poprzednim przykładzie uzyskaliśmy typ java.lang.String natomiast w obecnym typ String. Typ String został podobnie jak wszystkie typy Scali jest wrapperem który w procesie kompilacji zostanie przetłumaczony na typ java.lang.String.
Warto w tym miejscu wspomnieć że w Scali nie istnieją typy proste, a jedynie obiekty. Wspomniane definicje obiektów jak również definicje użytecznych funkcji języka Scala znajdują się w pliku Predef.scala w bibliotece Scali. Plik ten jest zawsze domyślnie importowany w każdym kodzie w sposób nie jawny.
Jedną z użytecznych funkcji zdefiniowanych w w/w pliku jest println:
scala> println(helloWorld)
Hello world!
Warto tutaj jeszcze wspomnieć o ciekawej właściwości naszego interpretera Scali, mianowicie o automatycznym nazywaniu zmiennych które zdefiniujemy na stosie w sposób anonimowy:
scala> "new message from space"
res3: java.lang.String = "new message from space"
W tym momencie widzimy że została automatycznie wygenerowana nazwa zmiennej res3 którą zresztą możemy w każdej chwili wykorzystać:
scala> println(res3)
new message from space
Przyszła teraz kolej na zdefiniowanie naszej pierwszej funkcji, robimy to w sposób następujący z użyciem słowa kluczowego def:
scala> def fun() { println("fun") }
fun: ()Unit
Proszę zwrócić uwagę na typ zwracany przez naszą funkcje Unit, w związku z tym że nie oczekiwaliśmy żadnego wyniku funkcji, został on domyślnie zdefiniowany. Unit jest w w Scali typem nie określnym (znanym z Javy jako void).
Poniżej znajduje się definicja funkcji której zwracana wartość jest istotna:
scala> def five() = { 5 }
five: ()Int
Należy zauważyć w tym przykładzie iż Scala podobnie jak Ruby nie wykorzystuje słowa kluczowego return do zwrócenia wartości. Następujący przykład pozwoli nam zrozumieć ten fakt, zwracając przy okazji uwagę na to że w Scali if podobnie jak konstrukcja w Javie ?: zwraca wartość jak normalna funkcja.
scala> def maximum(x:Int, y:Int) = { if (x>y) x else y }
maximum: (Int,Int)Int
W w/w przykładzie widzimy również że podobnie jak to miało miejsce w definicji zmiennych tak również w tym miejscu Scala potrafi “domyśleć” się typu zwracanego. Ta właściwość będzie jeszcze nie jednokrotnie widoczna w trakcie nauki Scali i to w sposób o wiele bardziej zaawansowany.
Na koniec chciałbym zostawić czytelnika z przykładem do przemyślenia :
scala> List(1, 2, 3, 4, 5).foreach( (x) => println(x) )
scala> List(1, 2, 3, 4, 5).foreach( x => println(x) )
scala> List(1, 2, 3, 4, 5).foreach( println _ )
Wszystkie 3 przykłady są tożsame, i oczywiście wynik ich działanie jest identyczny. Jako dodatkowy przykład wykorzystania '_' przedstawiam:
import Predef._
który powinien rzucić trochę światła na nasz poprzedni przykład. W następnym odcinku zacznę od szczegółowego wyjaśnienia magicznego '_'. Zainteresowanych i niecierpliwych już teraz zapraszam do korzystania ze strony domowej Scali scala-lang.org gdzie zawsze można zdobyć dodatkowe informacje. Polecam również zaglądanie do źródeł samej biblioteki Scali jako źródła informacji o Scali.


