From 61e4ed542721b2e64f93d13b4e69d13713d50a67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Wy=C5=82uda?= Date: Tue, 10 Jan 2017 11:45:35 +0100 Subject: [PATCH 1/4] Polish translation of the Scala tutorial --- pl/tutorials/tour/abstract-types.md | 79 ++++++++++ pl/tutorials/tour/annotations.md | 146 ++++++++++++++++++ .../tour/anonymous-function-syntax.md | 54 +++++++ pl/tutorials/tour/automatic-closures.md | 73 +++++++++ pl/tutorials/tour/case-classes.md | 143 +++++++++++++++++ pl/tutorials/tour/classes.md | 53 +++++++ pl/tutorials/tour/compound-types.md | 52 +++++++ pl/tutorials/tour/currying.md | 41 +++++ pl/tutorials/tour/default-parameter-values.md | 72 +++++++++ .../tour/explicitly-typed-self-references.md | 108 +++++++++++++ pl/tutorials/tour/extractor-objects.md | 42 +++++ pl/tutorials/tour/generic-classes.md | 49 ++++++ pl/tutorials/tour/higher-order-functions.md | 42 +++++ pl/tutorials/tour/implicit-conversions.md | 52 +++++++ pl/tutorials/tour/implicit-parameters.md | 58 +++++++ pl/tutorials/tour/inner-classes.md | 98 ++++++++++++ pl/tutorials/tour/local-type-inference.md | 63 ++++++++ pl/tutorials/tour/lower-type-bounds.md | 56 +++++++ pl/tutorials/tour/mixin-class-composition.md | 57 +++++++ pl/tutorials/tour/named-parameters.md | 37 +++++ pl/tutorials/tour/nested-functions.md | 35 +++++ pl/tutorials/tour/operators.md | 38 +++++ pl/tutorials/tour/pattern-matching.md | 45 ++++++ pl/tutorials/tour/polymorphic-methods.md | 30 ++++ .../tour/regular-expression-patterns.md | 39 +++++ pl/tutorials/tour/sequence-comprehensions.md | 68 ++++++++ pl/tutorials/tour/singleton-objects.md | 70 +++++++++ pl/tutorials/tour/tour-of-scala.md | 46 ++++++ pl/tutorials/tour/traits.md | 56 +++++++ pl/tutorials/tour/unified-types.md | 48 ++++++ pl/tutorials/tour/upper-type-bounds.md | 51 ++++++ pl/tutorials/tour/variances.md | 41 +++++ pl/tutorials/tour/xml-processing.md | 62 ++++++++ 33 files changed, 2004 insertions(+) create mode 100644 pl/tutorials/tour/abstract-types.md create mode 100644 pl/tutorials/tour/annotations.md create mode 100644 pl/tutorials/tour/anonymous-function-syntax.md create mode 100644 pl/tutorials/tour/automatic-closures.md create mode 100644 pl/tutorials/tour/case-classes.md create mode 100644 pl/tutorials/tour/classes.md create mode 100644 pl/tutorials/tour/compound-types.md create mode 100644 pl/tutorials/tour/currying.md create mode 100644 pl/tutorials/tour/default-parameter-values.md create mode 100644 pl/tutorials/tour/explicitly-typed-self-references.md create mode 100644 pl/tutorials/tour/extractor-objects.md create mode 100644 pl/tutorials/tour/generic-classes.md create mode 100644 pl/tutorials/tour/higher-order-functions.md create mode 100644 pl/tutorials/tour/implicit-conversions.md create mode 100644 pl/tutorials/tour/implicit-parameters.md create mode 100644 pl/tutorials/tour/inner-classes.md create mode 100644 pl/tutorials/tour/local-type-inference.md create mode 100644 pl/tutorials/tour/lower-type-bounds.md create mode 100644 pl/tutorials/tour/mixin-class-composition.md create mode 100644 pl/tutorials/tour/named-parameters.md create mode 100644 pl/tutorials/tour/nested-functions.md create mode 100644 pl/tutorials/tour/operators.md create mode 100644 pl/tutorials/tour/pattern-matching.md create mode 100644 pl/tutorials/tour/polymorphic-methods.md create mode 100644 pl/tutorials/tour/regular-expression-patterns.md create mode 100644 pl/tutorials/tour/sequence-comprehensions.md create mode 100644 pl/tutorials/tour/singleton-objects.md create mode 100644 pl/tutorials/tour/tour-of-scala.md create mode 100644 pl/tutorials/tour/traits.md create mode 100644 pl/tutorials/tour/unified-types.md create mode 100644 pl/tutorials/tour/upper-type-bounds.md create mode 100644 pl/tutorials/tour/variances.md create mode 100644 pl/tutorials/tour/xml-processing.md diff --git a/pl/tutorials/tour/abstract-types.md b/pl/tutorials/tour/abstract-types.md new file mode 100644 index 0000000000..ae514cf46f --- /dev/null +++ b/pl/tutorials/tour/abstract-types.md @@ -0,0 +1,79 @@ +--- +layout: tutorial +title: Typy abstrakcyjne + +disqus: true + +tutorial: scala-tour +num: 22 +languages: [ba, es, ko, pl] +language: pl +tutorial-next: compound-types +tutorial-previous: inner-classes +--- + +W Scali, klasy są parametryzowane wartościami (parametry konstruktora) oraz typami (jeżeli klasa jest [generyczna](generic-classes.html)). Aby zachować regularność, zarówno typy jak i wartości są elementami klasy. Analogicznie, mogą być konkretne albo abstrakcyjne. + +Poniższy przykład definiuje wartość określaną przez abstrakcyjny typ, będący elementem [cechy](traits.html) `Buffer`: + +```tut +trait Buffer { + type T + val element: T +} +``` + +*Typy abstrakcyjne* są typami, które nie są jednoznacznie określone. W powyższym przykładzie wiemy tylko, że każdy obiekt klasy `Buffer` posiada typ `T`, ale definicja klasy `Buffer` nie zdradza jakiemu konkretnie typowi odpowiada `T`. Tak jak definicje wartość, możemy także nadpisać definicje typów w klasach pochodnych. Pozwala to nam na odkrywanie dodatkowych informacji o abstrakcyjnym typie poprzez zawężanie jego ograniczeń (które opisują możliwe warianty konkretnego typu). + +W poniższym programie definiujemy klasę `SeqBuffer`, która ogranicza możliwe typy `T` do pochodnych sekwencji `Seq[U]` dla nowego typu `U`: + +```tut +abstract class SeqBuffer extends Buffer { + type U + type T <: Seq[U] + def length = element.length +} +``` + +Cechy oraz [klasy](classes.html) z abstrakcyjnymi typami są często używane w połączeniu z anonimowymi klasami. Aby to zilustrować wykorzystamy program, w którym utworzymy bufor sekwencji, ograniczony do listy liczb całkowitych: + +```tut +abstract class IntSeqBuffer extends SeqBuffer { + type U = Int +} + +object AbstractTypeTest1 extends App { + def newIntSeqBuf(elem1: Int, elem2: Int): IntSeqBuffer = + new IntSeqBuffer { + type T = List[U] + val element = List(elem1, elem2) + } + val buf = newIntSeqBuf(7, 8) + println("length = " + buf.length) + println("content = " + buf.element) +} +``` + +Typ zwracany przez metodę `newIntSeqBuf` nawiązuje do specjalizacji cechy `Buffer`, w której typ `U` jest równy `Int`. Podobnie w anonimowej klasie tworzonej w metodzie `newIntSeqBuf` określamy `T` jako `List[Int]`. + +Warto zwrócić uwagę na to, że często jest możliwa zamiana abstrakcyjnych typów w parametry typów klas i odwrotnie. Poniższy przykład stosuje wyłącznie parametry typów: + +```tut +abstract class Buffer[+T] { + val element: T +} +abstract class SeqBuffer[U, +T <: Seq[U]] extends Buffer[T] { + def length = element.length +} +object AbstractTypeTest2 extends App { + def newIntSeqBuf(e1: Int, e2: Int): SeqBuffer[Int, Seq[Int]] = + new SeqBuffer[Int, List[Int]] { + val element = List(e1, e2) + } + val buf = newIntSeqBuf(7, 8) + println("length = " + buf.length) + println("content = " + buf.element) +} +``` + +Należy pamięctać o tym, żeby zastosować [adnotacji wariancji](variance.html). Inaczej nie byłoby możliwe ukrycie konkretnego typu sekwencji obiektu zwracanego przez metodę `newIntSeqBuf`. diff --git a/pl/tutorials/tour/annotations.md b/pl/tutorials/tour/annotations.md new file mode 100644 index 0000000000..649ae464c2 --- /dev/null +++ b/pl/tutorials/tour/annotations.md @@ -0,0 +1,146 @@ +--- +layout: tutorial +title: Adnotacje + +disqus: true + +tutorial: scala-tour +num: 31 +tutorial-next: default-parameter-values +tutorial-previous: automatic-closures +language: pl +--- + +Adnotacje dodają meta-informacje do różnego rodzaju definicji. + +Podstawową formą adnotacji jest `@C` lub `@C(a1, ..., an)`. Tutaj `C` jest konstruktorem klasy `C`, który musi odpowiadać klasie `scala.Annotation`. Wszystkie argumenty konstruktora `a1, ..., an` muszą być stałymi wyrażeniami (czyli wyrażeniami takimi jak liczby, łańcuchy znaków, literały klasowe, enumeracji Javy oraz ich jednowymiarowe tablice). + +Adnotację stosuje się do pierwszej definicji lub deklaracji która po niej następuje. Możliwe jest zastosowanie więcej niż jednej adnotacji przed definicją lub deklaracją. Kolejność według której są one określone nie ma istotnego znaczenia. + +Znaczenie adnotacji jest zależne od implementacji. Na platformie Java, poniższe adnotacje mają standardowe znaczenie: + +| Scala | Java | +| ------ | ------ | +| [`scala.SerialVersionUID`](http://www.scala-lang.org/api/2.9.1/scala/SerialVersionUID.html) | [`serialVersionUID`](http://java.sun.com/j2se/1.5.0/docs/api/java/io/Serializable.html#navbar_bottom) (pole) | +| [`scala.cloneable`](http://www.scala-lang.org/api/2.9.1/scala/cloneable.html) | [`java.lang.Cloneable`](http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Cloneable.html) | +| [`scala.deprecated`](http://www.scala-lang.org/api/2.9.1/scala/deprecated.html) | [`java.lang.Deprecated`](http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Deprecated.html) | +| [`scala.inline`](http://www.scala-lang.org/api/2.9.1/scala/inline.html) (since 2.6.0) | brak odpowiednika | +| [`scala.native`](http://www.scala-lang.org/api/2.9.1/scala/native.html) (since 2.6.0) | [`native`](http://java.sun.com/docs/books/tutorial/java/nutsandbolts/_keywords.html) (słowo kluczowe) | +| [`scala.remote`](http://www.scala-lang.org/api/2.9.1/scala/remote.html) | [`java.rmi.Remote`](http://java.sun.com/j2se/1.5.0/docs/api/java/rmi/Remote.html) | +| [`scala.serializable`](http://www.scala-lang.org/api/2.9.1/index.html#scala.annotation.serializable) | [`java.io.Serializable`](http://java.sun.com/j2se/1.5.0/docs/api/java/io/Serializable.html) | +| [`scala.throws`](http://www.scala-lang.org/api/2.9.1/scala/throws.html) | [`throws`](http://java.sun.com/docs/books/tutorial/java/nutsandbolts/_keywords.html) (słowo kluczowe) | +| [`scala.transient`](http://www.scala-lang.org/api/2.9.1/scala/transient.html) | [`transient`](http://java.sun.com/docs/books/tutorial/java/nutsandbolts/_keywords.html) (słowo kluczowe) | +| [`scala.unchecked`](http://www.scala-lang.org/api/2.9.1/scala/unchecked.html) (od 2.4.0) | brak odpowiednika | +| [`scala.volatile`](http://www.scala-lang.org/api/2.9.1/scala/volatile.html) | [`volatile`](http://java.sun.com/docs/books/tutorial/java/nutsandbolts/_keywords.html) (słowo kluczowe) | +| [`scala.reflect.BeanProperty`](http://www.scala-lang.org/api/2.9.1/scala/reflect/BeanProperty.html) | [`Design pattern`](http://docs.oracle.com/javase/tutorial/javabeans/writing/properties.html) | + +W poniższym przykładzie dodajemy adnotację `throws` do definicji metody `read` w celu obsługi rzuconego wyjątku w programie w Javie. + +> Kompilator Javy sprawdza czy program zawiera obsługę dla [wyjątków kontrolowanych](http://docs.oracle.com/javase/tutorial/essential/exceptions/index.html) poprzez sprawdzenie które wyjątki mogą być wynikiem wykonania metody lub konstruktora. Dla każdego kontrolowanego wyjątki który może być wynikiem wykonania, adnotacja **throws** musi określić klasę tego wyjątku lub jedną z jej klas bazowych. +> Ponieważ Scala nie pozwala na definiowanie wyjątków kontrolowanych, jeżeli chcemy móc obsłużyć wyjątek z kodu w Scali w Javie, należy dodać jedną lub więcej adnotacji `throws` określające klasy wyjątek przez nią rzucanych. + +``` +package examples +import java.io._ +class Reader(fname: String) { + private val in = new BufferedReader(new FileReader(fname)) + @throws(classOf[IOException]) + def read() = in.read() +} +``` + +Poniższy program w Javie wypisuje zawartość pliku, którego nazwa jest podana jako pierwszy argument w metodzie `main`: + +``` +package test; +import examples.Reader; // Klasa Scali !! +public class AnnotaTest { + public static void main(String[] args) { + try { + Reader in = new Reader(args[0]); + int c; + while ((c = in.read()) != -1) { + System.out.print((char) c); + } + } catch (java.io.IOException e) { + System.out.println(e.getMessage()); + } + } +} +``` + +Zakomentowanie adnotacji `throws` w klasie `Reader` spowoduje poniższy błąd kompilacji głównego programu w Javie: + +``` +Main.java:11: exception java.io.IOException is never thrown in body of +corresponding try statement + } catch (java.io.IOException e) { + ^ +1 error +``` + +### Adnotacje Javy ### + +Java w wersji 1.5 wprowadziła możliwość definiowania metadanych przez użytkownika w postaci [adnotacji](https://docs.oracle.com/javase/tutorial/java/annotations/). Kluczową cechą adnotacji jest to, że polegają one na określaniu par nazwa-wartość w celu inicjalizacji jej elementów. Na przykład, jeżeli potrzebujemy adnotacji w celu śledzenia źródeł pewnej klasy, możemy ją zdefiniować w następujący sposób: + +``` +@interface Source { + public String URL(); + public String mail(); +} +``` + +I następnie zastosować w taki sposób: + +``` +@Source(URL = "http://coders.com/", + mail = "support@coders.com") +public class MyClass extends HisClass ... +``` + +Zastosowanie adnotacji w Scali wygląda podobnie jak wywołanie konstruktora, gdzie wymagane jest podanie nazwanych argumentów: + +``` +@Source(URL = "http://coders.com/", + mail = "support@coders.com") +class MyScalaClass ... +``` + +Składnia ta może się wydawać nieco nadmiarowa, jeżeli adnotacja składa się tylko z jednego elmentu (bez wartości domyślnej), zatem jeżeli nazwa pola jest określona jako `value`, może być ona stosowana w Javie stosując składnię podobną do konstruktora: + +``` +@interface SourceURL { + public String value(); + public String mail() default ""; +} +``` + +Następnie ją można zastosować: + +``` +@SourceURL("http://coders.com/") +public class MyClass extends HisClass ... +``` + +W tym przypadku, Scala daje taką samą możliwość: + +``` +@SourceURL("http://coders.com/") +class MyScalaClass ... +``` + +Element `mail` został zdefiniowany z wartością domyślną, zatem nie musimy jawnie określać wartości dla niego. Jednakże, jeżeli chcemy tego dokonać, Java nie pozwala nam na mieszanie tych styli: + +``` +@SourceURL(value = "http://coders.com/", + mail = "support@coders.com") +public class MyClass extends HisClass ... +``` + +Scala daje nam większą elastyczność w tym aspekcie: + +``` +@SourceURL("http://coders.com/", + mail = "support@coders.com") + class MyScalaClass ... +``` diff --git a/pl/tutorials/tour/anonymous-function-syntax.md b/pl/tutorials/tour/anonymous-function-syntax.md new file mode 100644 index 0000000000..e292844f1b --- /dev/null +++ b/pl/tutorials/tour/anonymous-function-syntax.md @@ -0,0 +1,54 @@ +--- +layout: tutorial +title: Funkcje anonimowe + +disqus: true + +tutorial: scala-tour +num: 6 +language: pl +tutorial-next: higher-order-functions +tutorial-previous: mixin-class-composition +--- + +Scala posiada lekką składnię pozwalającą na definiowanie funkcji anonimowych. Poniższe wyrażenie tworzy funkcję następnika dla liczb całkowitych: + +```tut +(x: Int) => x + 1 +``` + +Jest to krótsza forma deklaracji anonimowej klasy: + +```tut +new Function1[Int, Int] { + def apply(x: Int): Int = x + 1 +} +``` + +Możliwe jest także zdefiniowanie funkcji z wieloma parametrami: + +```tut +(x: Int, y: Int) => "(" + x + ", " + y + ")" +``` + +lub też bez parametrów: + +```tut +() => { System.getProperty("user.dir") } +``` + +Istnieje także prosty sposób definicji typów funkcji. Dla powyższych funkcji można je określić w następujący sposób: + +``` +Int => Int +(Int, Int) => String +() => String +``` + +Jest to skrócona forma dla poniższych typów: + +``` +Function1[Int, Int] +Function2[Int, Int, String] +Function0[String] +``` diff --git a/pl/tutorials/tour/automatic-closures.md b/pl/tutorials/tour/automatic-closures.md new file mode 100644 index 0000000000..26d30abf26 --- /dev/null +++ b/pl/tutorials/tour/automatic-closures.md @@ -0,0 +1,73 @@ +--- +layout: tutorial +title: Automatyczna konstrukcja domknięć + +disqus: true + +tutorial: scala-tour +num: 30 +language: pl +tutorial-next: annotations +tutorial-previous: operators +--- + +Scala pozwala na przekazywanie funkcji bezparametrycznych jako argumenty dla metod. Kiedy tego typu metoda jest wywołana, właściwe parametry dla funkcji bezparametrycznych nie są ewaluowane i przekazywana jest pusta funkcja, która enkapsuluje obliczenia odpowiadającego parametru (tzw. *wywołanie-przez-nazwę*). + +Poniższy kod demonstruje działanie tego mechanizmu: + +```tut +object TargetTest1 extends App { + def whileLoop(cond: => Boolean)(body: => Unit): Unit = + if (cond) { + body + whileLoop(cond)(body) + } + var i = 10 + whileLoop (i > 0) { + println(i) + i -= 1 + } +} +``` + +Funkcja `whileLoop` pobiera dwa parametry: `cond` i `body`. Kiedy funkcja jest aplikowana, jej właściwe parametry nie są ewaluowane. Lecz gdy te parametry są wykorzystane w ciele `whileLoop`, zostanie ewaluowana niejawnie utworzona funkcja, zwracająca ich prawdziwą wartość. Zatem metoda `whileLoop` implementuje rekursywnie pętlę while w stylu Javy. + +Możemy połączyć ze sobą wykorzystanie [operatorów infiksowych/postfiksowych](operators.html) z tym mechanizmem aby utworzyć bardziej złożone wyrażenia. + +Oto implementacja pętli w stylu wykonaj-dopóki: + +```tut +object TargetTest2 extends App { + def loop(body: => Unit): LoopUnlessCond = + new LoopUnlessCond(body) + protected class LoopUnlessCond(body: => Unit) { + def unless(cond: => Boolean) { + body + if (!cond) unless(cond) + } + } + var i = 10 + loop { + println("i = " + i) + i -= 1 + } unless (i == 0) +} +``` + +Funkcja `loop` przyjmuje ciało pętli oraz zwraca instancję klasy `LoopUnlessCond` (która enkapsuluje to ciało). Warto zwrócić uwagę, że ciało tej funkcji nie zostało jeszcze ewaluowane. Klasa `LoopUnlessCond` posiada metodę `unless` którą możemy wykorzystać jako *operator infiksowy*. W ten sposób, uzyskaliśmy całkiem naturalną składnię dla naszej nowej pętli: `loop { < stats > } unless ( < cond > )`. + +Oto wynik działania programu `TargetTest2`: + +``` +i = 10 +i = 9 +i = 8 +i = 7 +i = 6 +i = 5 +i = 4 +i = 3 +i = 2 +i = 1 +``` + diff --git a/pl/tutorials/tour/case-classes.md b/pl/tutorials/tour/case-classes.md new file mode 100644 index 0000000000..92f546c5d4 --- /dev/null +++ b/pl/tutorials/tour/case-classes.md @@ -0,0 +1,143 @@ +--- +layout: tutorial +title: Klasy case + +disqus: true + +tutorial: scala-tour +num: 10 +language: pl +tutorial-next: pattern-matching +tutorial-previous: currying +--- + +Scala wspiera mechanizm _klas case_. Klasy case są zwykłymi klasami z dodatkowymi założeniami: + +* Domyślnie immutable +* Można je dekomponować poprzez [dopasowanie wzorca](pattern-matching.html) +* Porównywane poprzez podobieństwo strukturalne zamiast przez referencje +* Zwięzła składnia tworzenia obiektów i operacji na nich + +Poniższy przykład obrazuje hierarchię typów powiadomień, która składa się z abstrakcyjnej klasy `Notification` oraz trzech konkretnych rodzajów zaimplementowanych jako klasy case `Email`, `SMS` i `VoiceRecording`: + +```tut +abstract class Notification +case class Email(sourceEmail: String, title: String, body: String) extends Notification +case class SMS(sourceNumber: String, message: String) extends Notification +case class VoiceRecording(contactName: String, link: String) extends Notification +``` + +Tworzenie obiektu jest bardzo proste: (Zwróć uwagę na to, że słowo `new` nie jest wymagane) + +```tut +val emailFromJohn = Email("john.doe@mail.com", "Greetings From John!", "Hello World!") +``` + +Parametry konstruktora klasy case są traktowane jako publiczne wartości i można się do nich odwoływać bezpośrednio: + +```tut +val title = emailFromJohn.title +println(title) // wypisuje "Greetings From John!" +``` + +W klasach case nie można modyfikować wartości pól. (Z wyjątkiem sytuacji kiedy dodasz `var` przed nazwą pola) + +```tut:fail +emailFromJohn.title = "Goodbye From John!" // Jest to błąd kompilacji, gdyż pola klasy case są domyślnie immutable +``` + +Zamiast tego, możesz utworzyć kopię używając metody `copy`: + +```tut +val editedEmail = emailFromJohn.copy(title = "I am learning Scala!", body = "It's so cool!") + +println(emailFromJohn) // wypisuje "Email(john.doe@mail.com,Greetings From John!,Hello World!)" +println(editedEmail) // wypisuje "Email(john.doe@mail.com,I am learning Scala,It's so cool!)" +``` + +Dla każdej klasy case kompilator Scali generuje metodę `equals`, która implementuje strukturalne porównanie obiektów oraz metodę `toString`. Przykład: + +```tut +val firstSms = SMS("12345", "Hello!") +val secondSms = SMS("12345", "Hello!") + +if (firstSms == secondSms) { + println("They are equal!") +} + +println("SMS is: " + firstSms) +``` + +Wypisze: + +``` +They are equal! +SMS is: SMS(12345, Hello!) +``` + +Jednym z najważniejszych zastosowań klas case (skąd też się wzięła ich nazwa), jest **dopasowanie wzorca**. Poniższy przykład pokazuje działanie funkcji, która zwraca różne komunikaty, w zależności od rodzaju powiadomienia: + +```tut +def showNotification(notification: Notification): String = { + notification match { + case Email(email, title, _) => + "You got an email from " + email + " with title: " + title + case SMS(number, message) => + "You got an SMS from " + number + "! Message: " + message + case VoiceRecording(name, link) => + "you received a Voice Recording from " + name + "! Click the link to hear it: " + link + } +} + +val someSms = SMS("12345", "Are you there?") +val someVoiceRecording = VoiceRecording("Tom", "voicerecording.org/id/123") + +println(showNotification(someSms)) +println(showNotification(someVoiceRecording)) + +// wypisuje: +// You got an SMS from 12345! Message: Are you there? +// you received a Voice Recording from Tom! Click the link to hear it: voicerecording.org/id/123 +``` + +Poniżej bardziej skomplikowany przykład używający `if` w celu określenia dodatkowych warunków dopasowania: + +```tut +def showNotificationSpecial(notification: Notification, specialEmail: String, specialNumber: String): String = { + notification match { + case Email(email, _, _) if email == specialEmail => + "You got an email from special someone!" + case SMS(number, _) if number == specialNumber => + "You got an SMS from special someone!" + case other => + showNotification(other) // nic szczególnego, wywołaj domyślną metodę showNotification + } +} + +val SPECIAL_NUMBER = "55555" +val SPECIAL_EMAIL = "jane@mail.com" +val someSms = SMS("12345", "Are you there?") +val someVoiceRecording = VoiceRecording("Tom", "voicerecording.org/id/123") +val specialEmail = Email("jane@mail.com", "Drinks tonight?", "I'm free after 5!") +val specialSms = SMS("55555", "I'm here! Where are you?") + +println(showNotificationSpecial(someSms, SPECIAL_EMAIL, SPECIAL_NUMBER)) +println(showNotificationSpecial(someVoiceRecording, SPECIAL_EMAIL, SPECIAL_NUMBER)) +println(showNotificationSpecial(specialEmail, SPECIAL_EMAIL, SPECIAL_NUMBER)) +println(showNotificationSpecial(specialSms, SPECIAL_EMAIL, SPECIAL_NUMBER)) + +// wypisuje: +// You got an SMS from 12345! Message: Are you there? +// you received a Voice Recording from Tom! Click the link to hear it: voicerecording.org/id/123 +// You got an email from special someone! +// You got an SMS from special someone! + +``` + +Programując w Scali, zachęca się abyś jak najszerzej używał klas case do modelowania danych, jako że kod który je wykorzystuje jest bardziej ekspresywny i łatwiejszy do utrzymania: + +* Obiekty typu immutable uwalniają cię od potrzeby śledzenia zmian stanu +* Porównanie przez wartość pozwala na porównywanie instancji tak jakby były prymitywnymi wartościami +* Dopasowanie wzorca znacząco upraszcza logikę rozgałęzień, co prowadzi do mniejszej ilości błędów i czytelniejszego kodu + + diff --git a/pl/tutorials/tour/classes.md b/pl/tutorials/tour/classes.md new file mode 100644 index 0000000000..dee935059d --- /dev/null +++ b/pl/tutorials/tour/classes.md @@ -0,0 +1,53 @@ +--- +layout: tutorial +title: Klasy + +disqus: true + +tutorial: scala-tour +num: 3 +language: pl +tutorial-next: traits +tutorial-previous: unified-types +--- + +Klasy w Scali określają schemat obiektów podczas wykonania programu. Oto przykład definicji klasy `Point`: + +```tut +class Point(var x: Int, var y: Int) { + def move(dx: Int, dy: Int): Unit = { + x = x + dx + y = y + dy + } + override def toString: String = + "(" + x + ", " + y + ")" +} +``` + +Klasy w Scali są sparametryzowane poprzez argumenty konstruktora. Powyższy kod wymaga podania dwóch argumentów konstruktora: `x` i `y`. Oba parametry są widoczne w zasięgu ciała klasy. + +Klasa `Point` zawiera także dwie metody: `move` i `toString`. `move` pobiera dwa argumenty w postaci liczb całkowitych, ale nie zwraca żadnej wartości (zwracany typ `Unit` odpowiada `void` w językach takich jak Java). Z drugiej strony `toString` nie wymaga żadnych parametrów, ale zwraca łańcuch znaków typu `String`. Ponieważ `toString` przesłania predefiniowaną metodę `toString`, jest ona oznaczona słowem kluczowym `override`. + +Należy dodać, że w Scali nie jest wymagane podanie słowa kluczowego `return` w celu zwrócenia wartości. Dzięki temu, że każdy blok kodu w Scali jest wyrażeniem, wartością zwracaną przez metodę jest ostatnie wyrażenie w ciele metody. Dodatkowo proste wyrażenia, takie jak zaprezentowane na przykładzie implementacji `toString` nie wymagają podania klamer, zatem można je umieścić bezpośrednio po definicji metody. + +Instancje klasy można tworzyć w następujący sposób: + +```tut +object Classes { + def main(args: Array[String]) { + val pt = new Point(1, 2) + println(pt) + pt.move(10, 10) + println(pt) + } +} +``` + +Program definiuje wykonywalną aplikację w postaci [obiektu singleton](singleton-objects.html) z główną metodą `main`. Metoda `main` tworzy nową instancję typu `Point` i zapisuje ją do wartości `pt`. Istotną rzeczą jest to, że wartości zdefiniowane z użyciem słowa kluczowego `val` różnią się od zmiennych określonych przez `var` (jak w klasie `Point` powyżej), tym że nie dopuszczają aktualizacji ich wartości. + +Wynik działania programu: + +``` +(1, 2) +(11, 12) +``` diff --git a/pl/tutorials/tour/compound-types.md b/pl/tutorials/tour/compound-types.md new file mode 100644 index 0000000000..b0bedffc5a --- /dev/null +++ b/pl/tutorials/tour/compound-types.md @@ -0,0 +1,52 @@ +--- +layout: tutorial +title: Typy złożone + +disqus: true + +tutorial: scala-tour +num: 23 +language: pl +tutorial-next: explicitly-typed-self-references +tutorial-previous: abstract-types +--- + +Czasami konieczne jest wyrażenie, że dany typ jest podtypem kilku innych typów. W Scali wyraża się to za pomocą *typów złożonych*, które są częścią wspólną typów obiektów. + +Załóżmy że mamy dwie cechy `Cloneable` i `Resetable`: + +```tut +trait Cloneable extends java.lang.Cloneable { + override def clone(): Cloneable = { + super.clone().asInstanceOf[Cloneable] + } +} +trait Resetable { + def reset: Unit +} +``` + +Teraz chcielibyśmy napisać funkcję `cloneAndReset`, która przyjmuje obiekt, klonuje go i resetuje oryginalny obiekt: + +``` +def cloneAndReset(obj: ?): Cloneable = { + val cloned = obj.clone() + obj.reset + cloned +} +``` + +Pojawia się pytanie, jakiego typu powinen być parametr `obj`. Jeżeli jest to `Cloneable`, to dany obiekt może zostać sklonowany, ale nie zresetowany. W przypadku gdy jest to to `Resetable`, możemy go zresetować, ale nie mamy dostępu do operacji klonowania. Aby uniknąć rzutowania typów w tej sytuacji, możemy określić typ `obj` tak, aby był jednocześnie `Cloneable` i `Resetable`. Ten złożony typ jest zapisywany w taki sposób: `Cloneable with Resetable`. + +Zaktualizowana funkcja: + +``` +def cloneAndReset(obj: Cloneable with Resetable): Cloneable = { + //... +} +``` + +Typy złożone mogą składać się z kilku typów obiektów i mogą mieć tylko jedno wyrafinowanie, które może być użyte do zawężenia sygnatury istniejących elementów obiektu. +Przyjmują one postać: `A with B with C ... { wyrafinowanie }` + +Przykład użycia wyrafinowania typów jest pokazany na stronie o [typach abstrakcyjnych](abstract-types.html). diff --git a/pl/tutorials/tour/currying.md b/pl/tutorials/tour/currying.md new file mode 100644 index 0000000000..60fc81961d --- /dev/null +++ b/pl/tutorials/tour/currying.md @@ -0,0 +1,41 @@ +--- +layout: tutorial +title: Rozwijanie funkcji (Currying) + +disqus: true + +tutorial: scala-tour +num: 9 +language: pl +tutorial-next: case-classes +tutorial-previous: nested-functions +--- + +Funkcja może określić dowolną ilość list parametrów. Kiedy jest ona wywołana dla mniejszej liczby niż zostało to zdefiniowane, wtedy zwraca ona funkcję pobierającą dalsze listy parametrów jako jej argument. + +Przykład rozwijania funkcji: + +```tut +object CurryTest extends App { + + def filter(xs: List[Int], p: Int => Boolean): List[Int] = + if (xs.isEmpty) xs + else if (p(xs.head)) xs.head :: filter(xs.tail, p) + else filter(xs.tail, p) + + def modN(n: Int)(x: Int) = ((x % n) == 0) + + val nums = List(1, 2, 3, 4, 5, 6, 7, 8) + println(filter(nums, modN(2))) + println(filter(nums, modN(3))) +} +``` + +_Uwaga: metoda `modN` jest częściowo zastosowana dla dwóch wywołań `filter`, gdyż jest wywołana tylko dla jej pierwszego argumentu. Wyrażenie `modN(2)` zwraca funkcję typu `Int => Boolean` stąd też może być przekazane jako drugi argument funkcji `filter`._ + +Wynik działania powyższego programu: + +``` +List(2,4,6,8) +List(3,6) +``` diff --git a/pl/tutorials/tour/default-parameter-values.md b/pl/tutorials/tour/default-parameter-values.md new file mode 100644 index 0000000000..232cc3ea26 --- /dev/null +++ b/pl/tutorials/tour/default-parameter-values.md @@ -0,0 +1,72 @@ +--- +layout: tutorial +title: Domyślne wartości parametrów + +disqus: true + +tutorial: scala-tour +num: 32 +language: pl +tutorial-next: named-parameters +tutorial-previous: annotations +--- + +Scala zezwala na określenie domyślnych wartości dla parametrów co pozwala wyrażeniu wywołującemu ją na pominięcie tych parametrów. + +W Javie powszechną praktyką jest definiowanie implementacji metod, które służa wyłącznie określeniu domyślnych wartości dla pewnych parametrów dużych metod. Najczęściej stosuje się to w konstruktorach: + +```java +public class HashMap { + public HashMap(Map m); + /** Utwórz mapę z domyślną pojemnością (16) + * i loadFactor (0.75) + */ + public HashMap(); + /** Utwórz mapę z domyślnym loadFactor (0.75) */ + public HashMap(int initialCapacity); + public HashMap(int initialCapacity, float loadFactor); +} +``` + +Mamy tutaj do czynienia tylko z dwoma konstruktorami. Pierwszy przyjmuje inną mapę, a drugi wymaga podania pojemności i load factor. Trzeci oraz czwarty konstruktor pozwala użytkownikom `HashMap` na tworzenie instancji z domyślnymi wartościami tych parametrów, które są prawdopodobnie dobre w większości przypadków. + +Bardziej problematyczne jest to, że domyślne wartości są zarówno w Javadoc oraz w kodzie. Łatwo można zapomnieć o odpowiedniej aktualizacji tych wartości. Powszechnym wzorcem jest utworzenie publicznych stałych których wartości pojawią się w Javadoc: + +```java +public class HashMap { + public static final int DEFAULT_CAPACITY = 16; + public static final float DEFAULT_LOAD_FACTOR = 0.75; + + public HashMap(Map m); + /** Utwórz mapę z domyślną pojemnością (16) + * i loadFactor (0.75) + */ + public HashMap(); + /** Utwórz mapę z domyślnym loadFactor (0.75) */ + public HashMap(int initialCapacity); + public HashMap(int initialCapacity, float loadFactor); +} +``` + +Mimo że powstrzymuje to nas od powtarzania się, to podejście nie jest zbyt wyraziste. + +Scala wprowadza bezpośrednie wsparcie dla domyślnych parametrów: + +```tut +class HashMap[K,V](initialCapacity:Int = 16, loadFactor:Float = 0.75f) { +} + +// Używa domyślnych wartości +val m1 = new HashMap[String,Int] + +// initialCapacity 20, domyślny loadFactor +val m2 = new HashMap[String,Int](20) + +// nadpisujemy oba +val m3 = new HashMap[String,Int](20,0.8f) + +// nadpisujemy tylko loadFactor przez argumenty nazwane +val m4 = new HashMap[String,Int](loadFactor = 0.8f) +``` + +Należy zwrócić uwagę na to, w jaki sposób możemy wykorzystać *dowolną* domyślną wartość poprzez użycie [parametrów nazwanych](named-parameters.html). diff --git a/pl/tutorials/tour/explicitly-typed-self-references.md b/pl/tutorials/tour/explicitly-typed-self-references.md new file mode 100644 index 0000000000..0f5728f4bc --- /dev/null +++ b/pl/tutorials/tour/explicitly-typed-self-references.md @@ -0,0 +1,108 @@ +--- +layout: tutorial +title: Jawnie typowane samoreferencje + +disqus: true + +tutorial: scala-tour +num: 24 +language: pl +tutorial-next: implicit-parameters +tutorial-previous: compound-types +--- + +Dążąc do tego, aby nasze oprogramowanie było rozszerzalne, często przydatne okazuje się jawne deklarowanie typu `this`. Aby to umotywować, spróbujemy opracować rozszerzalną reprezentację grafu w Scali. + +Oto definicja opisująca grafy: + +```tut +abstract class Graph { + type Edge + type Node <: NodeIntf + abstract class NodeIntf { + def connectWith(node: Node): Edge + } + def nodes: List[Node] + def edges: List[Edge] + def addNode: Node +} +``` + +Grafy składają się z listy węzłów oraz krawędzi, gdzie zarówno typ węzłą jak i krawędzi są abstrakcyjne. Użycie [typów abstrakcyjnych](abstract-types.html) pozwala implementacjom cechy `Graph` na to by określały swoje konkretne klasy dla węzłów i krawędzi. Ponadto istnieje tutaj metoda `addNode`, której celem jest dodanie nowych węzłów do grafu. Węzły są połączone z użyciem metody `connectWith`. + +Przykład implementacji klasy `Graph`: + +```tut:fail +abstract class DirectedGraph extends Graph { + type Edge <: EdgeImpl + class EdgeImpl(origin: Node, dest: Node) { + def from = origin + def to = dest + } + class NodeImpl extends NodeIntf { + def connectWith(node: Node): Edge = { + val edge = newEdge(this, node) + edges = edge :: edges + edge + } + } + protected def newNode: Node + protected def newEdge(from: Node, to: Node): Edge + var nodes: List[Node] = Nil + var edges: List[Edge] = Nil + def addNode: Node = { + val node = newNode + nodes = node :: nodes + node + } +} +``` + +Klasa `DirectedGraph` częściowo implementuje i jednocześnie specjalizuje klasę `Graph`. Implementacja jest tylko częsciowa, ponieważ chcemy pozwolić na dalsze jej rozszerzanie. Dlatego szczegóły implementacyjne są pozostawione dla klas pochodnych co wymaga też określenia typu krawędzi oraz wierzchołków jako abstrakcyjne. Niemniej klasa `DirectedGraph` zawęża te typy do klas `EdgeImpl` oraz `NodeImpl`. + +Ponieważ konieczne jest udostępnienie możliwości tworzenia wierzchołków i krawędzi w naszej częściowej implementacji grafu, dodane zostały metody fabrykujące `newNode` oraz `newEdge`. Metody `addNode` wraz z `connectWith` są zdefiniowane na podstawie tych metod fabrykujących. + +Jeżeli przyjrzymy się bliżej implementacji metody `connectWith`, możemy dostrzec że tworząc krawędź, musimy przekazać samoreferencję `this` do metody fabrykującej `newEdge`. Lecz `this` jest już powązany z typem `NodeImpl`, który nie jest kompatybilny z typem `Node` ponieważ jest on tylko ograniczony z góry typem `NodeImpl`. Wynika z tego, iż powyższy program nie jest prawidłowy i kompilator Scali wyemituje błąd kompilacji. + +Scala rozwiązuje ten problem pozwalając na powiązanie klasy z innym typem poprzez jawne typowanie samoreferencji. Możemy użyć tego mechanizmu, aby naprawić powyższy kod: + +```tut +class NodeImpl extends NodeIntf { + self: Node => // określenie typu "self" + def connectWith(node: Node): Edge = { + val edge = newEdge(this, node) // w tej chwili się skompiluje + edges = edge :: edges + edge + } +} +``` + +W nowej definicji klasy `NodeImpl` referencja `this` jest typu `Node`. Ponieważ typ `Node` jest abstrakcyjny i stąd nie wiemy jeszczy, czy `NodeImpl` w rzeczywistości odpowiada `Node`, system typów w Scali nie pozwoli nam na utworzenie tego typu. Mimo wszystko za pomocą jawnej adnotacji typu stwierdzamy, że w pewnym momencie klasa pochodna od `NodeImpl` musi odpowiadać typowi `Node` aby dało się ją utworzyć. + +Oto konkretna specjalizacja `DirectedGraph`, gdzie abstrakcyjne elementy klasy mają ustalone konkretne znaczenie: + +```tut +class ConcreteDirectedGraph extends DirectedGraph { + type Edge = EdgeImpl + type Node = NodeImpl + protected def newNode: Node = new NodeImpl + protected def newEdge(f: Node, t: Node): Edge = + new EdgeImpl(f, t) +} +``` + +Należy dodać, że w tej klasie możemy utworzyć `NodeImpl` ponieważ wiemy już teraz, że `NodeImpl` określa klasę pochodną od `Node` (która jest zwyczajnie aliasem dla `NodeImpl`). + +Poniżej przykład zastosowania klasy `ConcreteDirectedGraph`: + +```tut +object GraphTest extends App { + val g: Graph = new ConcreteDirectedGraph + val n1 = g.addNode + val n2 = g.addNode + val n3 = g.addNode + n1.connectWith(n2) + n2.connectWith(n3) + n1.connectWith(n3) +} +``` diff --git a/pl/tutorials/tour/extractor-objects.md b/pl/tutorials/tour/extractor-objects.md new file mode 100644 index 0000000000..72a68ae0f7 --- /dev/null +++ b/pl/tutorials/tour/extractor-objects.md @@ -0,0 +1,42 @@ +--- +layout: tutorial +title: Obiekty ekstraktorów + +disqus: true + +tutorial: scala-tour +num: 15 +language: pl +tutorial-next: sequence-comprehensions +tutorial-previous: regular-expression-patterns +--- + +W Scali, wzorce mogą być zdefiniowane niezależnie od klas case. Obiekt posiadający metodę `unapply` może funkcjonować jako tak zwany ekstraktor. Jest to szczególna metoda, która pozwala na odwrócenie zastosowania obiektu dla pewnych danych. Jego celem jest ekstrakcja danych, z których został on utworzony. Dla przykładu, poniższy kod definiuje ekstraktor dla [obiektu](singleton-objects.html) `Twice`: + +```tut +object Twice { + def apply(x: Int): Int = x * 2 + def unapply(z: Int): Option[Int] = if (z%2 == 0) Some(z/2) else None +} + +object TwiceTest extends App { + val x = Twice(21) + x match { case Twice(n) => Console.println(n) } +} +``` + +Mamy tutaj do czynienia z dwiema konwencjami syntaktycznymi: + +Wyrażenie `case Twice(n)` prowadzi do wywołania `Twice.unapply`, który dopasowuje liczby parzyste. Wartość zwrócona przez metodę `unapply` określa czy argument został dopasowany lub nie, oraz wartość `n` wykorzystaną dalej w dopasowaniu danego przypadku. Tutaj jest to wartość `z/2`. + +Metoda `apply` nie jest konieczna do dopasowania wzorców. Jest jedynie wykorzystywana do udawania konstruktora. `Twice(21)` jest równoważne `Twice.apply(21)`. + +Typ zwracany przez `unapply` powinien odpowiadać jednemu przypadkowi: + +* Jeżeli jest to tylko test, należy zwrócić Boolean. Na przykład: `case even()` +* Jeżeli zwraca pojedynczą wartość typu T, powinien zwrócić `Option[T]` +* Jeżeli zwraca kilka wartości typów: `T1, ..., Tn`, należy je pogrupować jako opcjonalna krotka `Option[(T1, ..., Tn)]` + +Zdarza się, że chcielibyśmy dopasować określoną liczbę wartości oraz sekwencję. Z tego powodu, możesz także zdefiniować wzorce poprzez metodę `unapplySeq`. Ostatnia wartość typu `Tn` powinna być `Seq[S]`. Ten mechanizm pozwala na dopasowanie wzorców takich jak `case List(x1, ..., xn)`. + +Ekstraktory sprawiają, że kod jest łatwiejszy do utrzymania. Aby dowiedzieć się więcej, możesz przeczytać publikację ["Matching Objects with Patterns"](http://lamp.epfl.ch/~emir/written/MatchingObjectsWithPatterns-TR.pdf) (zobacz sekcję 4) autorstwa Emir, Odersky i Williams (styczeń 2007). diff --git a/pl/tutorials/tour/generic-classes.md b/pl/tutorials/tour/generic-classes.md new file mode 100644 index 0000000000..a4502cdc55 --- /dev/null +++ b/pl/tutorials/tour/generic-classes.md @@ -0,0 +1,49 @@ +--- +layout: tutorial +title: Klasy generyczne + +disqus: true + +tutorial: scala-tour +num: 17 +language: pl +tutorial-next: variances +tutorial-previous: sequence-comprehensions +--- + +Scala posiada wbudowaną obsługą klas parametryzowanych przez typy. Tego typu klasy generyczne są szczególnie użyteczne podczas tworzenia klas kolekcji. + +Poniższy przykład demonstruje zastosowanie parametrów generycznych: + +```tut +class Stack[T] { + var elems: List[T] = Nil + def push(x: T) { elems = x :: elems } + def top: T = elems.head + def pop() { elems = elems.tail } +} +``` + +Klasa `Stack` modeluje zmienny stos z zawierający elementy dowolnego typu `T`. Parametr `T` narzuca ograniczenie dla metod takie, że tylko elementy typu `T` mogą zostać dodane do stosu. Podobnie metoda `top` może zwrócić tylko elementy danego typu. + +Przykłady zastosowania: + +```tut +object GenericsTest extends App { + val stack = new Stack[Int] + stack.push(1) + stack.push('a') + println(stack.top) + stack.pop() + println(stack.top) +} +``` + +Wyjściem tego programu będzie: + +``` +97 +1 +``` + +_Uwaga: podtypowanie typów generycznych jest domyślnie określane jako invariant (niezmienne). Oznacza to, że mając stos znaków typu `Stack[Char]`, nie można go użyć jako stos typu `Stack[Int]`. Byłoby to błędne, ponieważ pozwalałoby to nam na wprowadzenie liczb całkowitych do stosu znaków. Zatem `Stack[T]` jest tylko podtypem `Stack[S]` jeżeli `S = T`. Ponieważ jednak jest to dość ograniczające, Scala posiada [mechanizm adnotacji parametrów typów](variances.html) pozwalający na kontrolę zachowania podtypowania typów generycznych._ diff --git a/pl/tutorials/tour/higher-order-functions.md b/pl/tutorials/tour/higher-order-functions.md new file mode 100644 index 0000000000..f5d5701514 --- /dev/null +++ b/pl/tutorials/tour/higher-order-functions.md @@ -0,0 +1,42 @@ +--- +layout: tutorial +title: Funkcje wyższego rzędu + +disqus: true + +tutorial: scala-tour +num: 7 +language: pl +tutorial-next: nested-functions +tutorial-previous: anonymous-function-syntax +--- + +Scala pozwala na definicję funkcji wyższego rzędu. Są to funkcje, które przyjmują funkcje jako parametry lub których wynik jest też funkcją. Poniżej znajduje się przykład funkcji `apply` który pobiera inną funkcję `f` i wartość `v`, po to by zwrócić wynik zastosowania `f` do `v`: + +```tut +def apply(f: Int => String, v: Int) = f(v) +``` + +_Uwaga: metody są automatycznie zamieniane na funkcje, jeżeli wymaga tego kontekst_ + +Praktyczny przykład: + +```tut +class Decorator(left: String, right: String) { + def layout[A](x: A) = left + x.toString() + right +} + +object FunTest extends App { + def apply(f: Int => String, v: Int) = f(v) + val decorator = new Decorator("[", "]") + println(apply(decorator.layout, 7)) +} +``` + +Wykonanie zwraca poniższy wynik: + +``` +[7] +``` + +W tym przykładzie, metoda `decorator.layout` jest automatycznie konwertowana do funkcji typu `Int => String` czego wymaga funkcja `apply`. Warto dodać, że metoda `decorator.layout` jest polimorficzna, co oznacza, że jej sygnatura jest odpowiednio dopasowana przez kompilator, dzięki czemu gdy jest przekazana do funkcji `apply`, jest ona traktowana jako `Int => String`. diff --git a/pl/tutorials/tour/implicit-conversions.md b/pl/tutorials/tour/implicit-conversions.md new file mode 100644 index 0000000000..84f20f9ac0 --- /dev/null +++ b/pl/tutorials/tour/implicit-conversions.md @@ -0,0 +1,52 @@ +--- +layout: tutorial +title: Konwersje implicit + +disqus: true + +tutorial: scala-tour +num: 26 +language: pl +tutorial-next: polymorphic-methods +tutorial-previous: implicit-parameters +--- + +Konwersja implicit z typu `S` do `T` jest określona przez wartość implicit, która jest funkcją typu `S => T` lub przez metodę implicit odpowiadającą funkcji tego typu. + +Konwersje implicit są stosowane w dwóch sytuacjach: + +* Jeżeli wyrażenie `e` jest typu `S` i `S` nie odpowiada wymaganemu typowi `T`. +* W przypadku wyboru `e.m` z `e` typu `T`, jeżeli `m` nie jest elementem `T`. + +W pierwszym przypadku wyszukiwana jest konwersja `c`, którą można zastosować do `e` aby uzyskać wynik typu `T`. +W drugim przypadku wyszukiwana jest konwersja `c`, którą można zastosować do `e` i której wyniki zawiera element nazwany `m`. + +Poniższa operacja na dwóch listach `xs` oraz `ys` typu `List[Int]` jest dopuszczalna: + +``` +xs <= ys +``` + +Zakładając, że metody implicit `list2ordered` oraz `int2ordered` zdefiniowane poniżej znajdują się w danym zakresie: + +``` +implicit def list2ordered[A](x: List[A]) + (implicit elem2ordered: A => Ordered[A]): Ordered[List[A]] = + new Ordered[List[A]] { /* .. */ } + +implicit def int2ordered(x: Int): Ordered[Int] = + new Ordered[Int] { /* .. */ } +``` + +Domyślnie importowany obiekt `scala.Predef` deklaruje kilka predefiniowanych typów (np. `Pair`) i metod (np. `assert`) ale także wiele użytecznych konwersji implicit. + +Przykładowo, kiedy wywołujemy metodę Javy, która wymaga typu `java.lang.Integer`, dopuszczalne jest przekazanie typu `scala.Int`. Dzieje się tak ponieważ `Predef` zawiera poniższe konwersje implicit: + +```tut +import scala.language.implicitConversions + +implicit def int2Integer(x: Int) = + java.lang.Integer.valueOf(x) +``` + +Aby zdefiniować własne konwersje implicit, należy zaimportować `scala.language.implicitConversions` (albo uruchomić kompilator z opcją `-language:implicitConversions`). Ta funkcjonalność musi być włączona jawnie, ze względu na problemy jakie mogą się wiązać z ich nadmiernym stosowaniem. diff --git a/pl/tutorials/tour/implicit-parameters.md b/pl/tutorials/tour/implicit-parameters.md new file mode 100644 index 0000000000..08d3ad454b --- /dev/null +++ b/pl/tutorials/tour/implicit-parameters.md @@ -0,0 +1,58 @@ +--- +layout: tutorial +title: Parametry implicit + +disqus: true + +tutorial: scala-tour +num: 25 +language: pl +tutorial-next: implicit-conversions +tutorial-previous: explicitly-typed-self-references +--- + +Metodę z _parametrami implicit_ można stosować tak samo jak zwyczajną metod. W takim przypadku etykieta `implicit` nie ma żadnego znaczenia. Jednak jeżeli odpowiednie argumenty dla parametrów implicit nie zostaną jawnie określone, to kompilator dostarczy je automatycznie. + +Argumenty które mogą być przekazywane jako parametry implicit można podzielić na dwie kategorie: + +* Najpierw dobierane są takie identyfikatory, które są dostępne bezpośrednio w punkcie wywołania metody i które określają definicję lub parametr implicit. +* W drugiej kolejności dobrane mogą być elementy modułów companion odpowiadających typom tych parametrów implicit, które są oznaczone jako `implicit`. + +W poniższym przykładzie zdefiniujemy metodę `sum`, która oblicza sumę listy elementów wykorzystując operacje `add` i `unit` obiektu `Monoid`. Należy dodać, że wartości implicit nie mogą być zdefiniowane globalnie, tylko muszą być elementem pewnego modułu. + +```tut +/** Ten przykład wykorzystuje strukturę z algebry abstrakcyjnej aby zilustrować działanie parametrów implicit. Półgrupa jest strukturą algebraiczną na zbiorze A z łączna (która spełnia warunek: add(x, add(y, z)) == add(add(x, y), z)) operacją nazwaną add, która łączy parę obiektów A by zwrócić inny A. */ +abstract class SemiGroup[A] { + def add(x: A, y: A): A +} +/** Monoid jest półgrupą z elementem neutralnym typu A, zwanym unit. Jest to element, który połączony z innym elementem (przez metodę add) zwróci ten sam element. */ +abstract class Monoid[A] extends SemiGroup[A] { + def unit: A +} +object ImplicitTest extends App { + /** Aby zademonstrować jak działają parametry implicit, najpierw zdefiniujemy monoidy dla łańcuchów znaków oraz liczb całkowitych. Słowo kluczowe implicit sprawia, że oznaczone nimi wartości mogą być użyte aby zrealizować parametry implicit. */ + implicit object StringMonoid extends Monoid[String] { + def add(x: String, y: String): String = x concat y + def unit: String = "" + } + implicit object IntMonoid extends Monoid[Int] { + def add(x: Int, y: Int): Int = x + y + def unit: Int = 0 + } + /** Metoda sum pobiera List[A] i zwraca A, który jest wynikiem zastosowania zastosowania monoidu do wszystkich kolejnych elementów listy. Oznaczając parametr m jako implicit sprawiamy, że potrzebne jest tylko podanie parametru xs podczas wywołania, ponieważ mamy już List[A], zatem wiemy jakiego typue jest w rzeczywistości A, zatem wiemy też jakiego typu Monoid[A] jest potrzebny. Możemy więc wyszukać wartość val lub obiekt w aktualnym zasięgu, który ma odpowiadający typu i użyć go bez jawnego określania referencji do niego. */ + def sum[A](xs: List[A])(implicit m: Monoid[A]): A = + if (xs.isEmpty) m.unit + else m.add(xs.head, sum(xs.tail)) + + /** Wywołamy tutaj dwa razy sum, podając za każdym razem tylko listę. Ponieważ drugi parametr (m) jest implicit, jego wartość jest wyszukiwana przez kompilator w aktualnym zasięgu, na podstawie typu monoidu wymaganego w każdym przypadku, co oznacza że oba wyrażenia mogą być w pełni ewaluowane. */ + println(sum(List(1, 2, 3))) // używa IntMonoid + println(sum(List("a", "b", "c"))) // używa StringMonoid +} +``` + +Wynik powyższego programu: + +``` +6 +abc +``` diff --git a/pl/tutorials/tour/inner-classes.md b/pl/tutorials/tour/inner-classes.md new file mode 100644 index 0000000000..5b711f283a --- /dev/null +++ b/pl/tutorials/tour/inner-classes.md @@ -0,0 +1,98 @@ +--- +layout: tutorial +title: Klasy wewnętrzne + +disqus: true + +tutorial: scala-tour +num: 21 +language: pl +tutorial-next: abstract-types +tutorial-previous: lower-type-bounds +--- + +W Scali możliwe jest zdefiniowanie klasy jako element innej klasy. W przeciwieństwie do języków takich jak Java, gdzie tego typu wewnętrzne klasy są elementami ujmujących ich klas, w Scali są one związane z zewnętrznym obiektem. Aby zademonstrować tę różnicę, stworzymy teraz prostą implementację grafu: + +```tut +class Graph { + class Node { + var connectedNodes: List[Node] = Nil + def connectTo(node: Node) { + if (connectedNodes.find(node.equals).isEmpty) { + connectedNodes = node :: connectedNodes + } + } + } + var nodes: List[Node] = Nil + def newNode: Node = { + val res = new Node + nodes = res :: nodes + res + } +} +``` + +W naszym programie grafy są reprezentowane przez listę wierzchołków. Wierzchołki są obiektami klasy wewnętrznej `Node`. Każdy wierzchołek zawiera listę sąsiadów, które są przechowywane w liście `connectedNodes`. Możemy teraz skonfigurować graf z kilkoma wierzchołkami i połączyć je ze sobą: + +```tut +object GraphTest extends App { + val g = new Graph + val n1 = g.newNode + val n2 = g.newNode + val n3 = g.newNode + n1.connectTo(n2) + n3.connectTo(n1) +} +``` + +Teraz wzbogacimy nasz przykład o jawne typowanie aby można było zobaczyć powiązanie typów wierzchołków z grafem: + +```tut +object GraphTest extends App { + val g: Graph = new Graph + val n1: g.Node = g.newNode + val n2: g.Node = g.newNode + val n3: g.Node = g.newNode + n1.connectTo(n2) + n3.connectTo(n1) +} +``` + +Ten kod pokazuje, że typ wierzchołka jest prefikowany przez swoją zewnętrzną instancję (która jest obiektem `g` w naszym przykładzie). Jeżeli mielibyśmy dwa grafy, system typów w Scali nie pozwoli nam na pomieszanie wierzchołków jednego z wierzchołkami drugiego, ponieważ wierzchołki innego grafu są określone innym przez inny typ. + +Przykład niedopuszczalnego programu: + +```tut:fail +object IllegalGraphTest extends App { + val g: Graph = new Graph + val n1: g.Node = g.newNode + val n2: g.Node = g.newNode + n1.connectTo(n2) // dopuszczalne + val h: Graph = new Graph + val n3: h.Node = h.newNode + n1.connectTo(n3) // niedopuszczalne! +} +``` + +Warto zwrócić uwagę na to, że ostatnia linia poprzedniego przykłady byłaby poprawnym programem w Javie. Dla wierzchołków obu grafów Java przypisałaby ten sam typ `Graph.Node`. W Scali także istnieje możliwość wyrażenia takiego typu, zapisując go w formie: `Graph#Node`. Jeżeli byśmy chcieli połączyć wierzchołki różnych grafów, musielibyśmy wtedy zmienić definicję implementacji naszego grafu w następujący sposób: + +```tut +class Graph { + class Node { + var connectedNodes: List[Graph#Node] = Nil + def connectTo(node: Graph#Node) { + if (connectedNodes.find(node.equals).isEmpty) { + connectedNodes = node :: connectedNodes + } + } + } + var nodes: List[Node] = Nil + def newNode: Node = { + val res = new Node + nodes = res :: nodes + res + } +} +``` + +> Ważne jest, że ten program nie pozwala nam na dołączenie wierzchołka do dwóch różnych grafów. Jeżeli byśmy chcieli znieść to ograniczenie, należy zmienić typ zmiennej `nodes` na `Graph#Node`. diff --git a/pl/tutorials/tour/local-type-inference.md b/pl/tutorials/tour/local-type-inference.md new file mode 100644 index 0000000000..c76d2551e1 --- /dev/null +++ b/pl/tutorials/tour/local-type-inference.md @@ -0,0 +1,63 @@ +--- +layout: tutorial +title: Lokalna inferencja typów + +disqus: true + +tutorial: scala-tour +num: 28 +language: pl +tutorial-next: operators +tutorial-previous: polymorphic-methods +--- + +Scala posiada wbudowany mechanizm inferencji typów, który pozwala programiście pominąć pewne informacje o typach. Przykładowo zazwyczaj nie wymaga się podawania typów zmiennych, gdyż kompilator sam jest w stanie go wydedukować na podstawie typu wyrażenia inicjalizacji zmiennej. Także typy zwracane przez metody mogą być często pominięte, ponieważ odpowiadają one typowi ciała metody, który jest inferowany przez kompilator. + +Oto przykład: + +```tut +object InferenceTest1 extends App { + val x = 1 + 2 * 3 // typem x jest Int + val y = x.toString() // typem y jest String + def succ(x: Int) = x + 1 // metoda succ zwraca wartości typu Int +} +``` + +Dla metod rekurencyjnych kompilator nie jest w stanie określić zwracanego typu. Oto przykład programu, który zakończy się niepowodzeniem kompilacji z tego powodu: + +```tut:fail +object InferenceTest2 { + def fac(n: Int) = if (n == 0) 1 else n * fac(n - 1) +} +``` + +Nie jest też konieczne określenie parametrów typu, kiedy są wywoływanie [metody polimorficzne](polymorphic-methods.html) lub kiedy tworzymy [klasy generyczne](generic-classes.html). Kompilator Scali sam określi typ brakujących parametrów typów na podstawie kontekstu oraz typów właściwych parametrów metody/konstruktora. + +Oto przykład który to ilustruje: + +``` +case class MyPair[A, B](x: A, y: B); +object InferenceTest3 extends App { + def id[T](x: T) = x + val p = MyPair(1, "scala") // typ: MyPair[Int, String] + val q = id(1) // typ: Int +} +``` + +Dwie ostatnie linie tego programu są równoważne poniższemu kodu, gdzie wszystkie inferowane typy są określone jawnie: + +``` +val x: MyPair[Int, String] = MyPair[Int, String](1, "scala") +val y: Int = id[Int](1) +``` + +W niektórych sytuacjach poleganie na inferencji typów w Scali może być niebezpieczne, tak jak demonstruje to poniższy program: + +```tut:fail +object InferenceTest4 { + var obj = null + obj = new Object() +} +``` + +Ten program się nie skompiluje, ponieważ typ określony dla zmiennej `obj` jest `Null`. Ponieważ jedyną wartością tego typu jest `null`, nie jest możliwe przypisanie tej zmiennej innej wartości. diff --git a/pl/tutorials/tour/lower-type-bounds.md b/pl/tutorials/tour/lower-type-bounds.md new file mode 100644 index 0000000000..8f78a6937e --- /dev/null +++ b/pl/tutorials/tour/lower-type-bounds.md @@ -0,0 +1,56 @@ +--- +layout: tutorial +title: Dolne ograniczenia typów + +disqus: true + +tutorial: scala-tour +num: 20 +language: pl +tutorial-next: inner-classes +tutorial-previous: upper-type-bounds +--- + +Podczas gdy [górne ograniczenia typów](upper-type-bounds.html) zawężają typ do podtypu innego typu, *dolne ograniczenia typów* określają dany typ jako typ bazowy innego typu. Sformułowanie `T >: A` wyraża, że parametr typowy `T` lub typ abstrakcyjny `T` odwołuje się do typu bazowego `A`. + +Oto przykład w którym jest to użyteczne: + +```tut +case class ListNode[T](h: T, t: ListNode[T]) { + def head: T = h + def tail: ListNode[T] = t + def prepend(elem: T): ListNode[T] = + ListNode(elem, this) +} +``` + +Powyższy program implementuje listę jednokierunkową z operacją dodania elementu na jej początek. Niestety typ ten jest niezmienny według parametru typu klasy `ListNode`, tzn. `ListNode[String]` nie jest podtypem `ListNode[Any]`. Z pomocą [adnotacji wariancji](variances.html) możemy wyrazić semantykę podtypowania: + +``` +case class ListNode[+T](h: T, t: ListNode[T]) { ... } +``` + +Niestety ten program się nie skompiluje, ponieważ adnotacja kowariancji może być zastosowana tylko jeżeli zmienna typu jest używana wyłącznie w pozycji kowariantnej. Jako że zmienna typu `T` występuje jako parametr typu metody `prepend`, ta zasada jest złamana. Z pomocą *dolnego ograniczenia typu*, możemy jednak zaimplementować tą metodę w taki sposób, że `T` występuje tylko w pozycji kowariantnej: + +```tut +case class ListNode[+T](h: T, t: ListNode[T]) { + def head: T = h + def tail: ListNode[T] = t + def prepend[U >: T](elem: U): ListNode[U] = + ListNode(elem, this) +} +``` + +_Uwaga:_ nowa wersja metody `prepend` ma mniej ograniczający typ. Przykładowo pozwala ona na dodanie obiektu typu bazowego elementów istniejącej listy. Wynikowa lista będzie listą tego typu bazowego. + +Przykład który to ilustruje: + +```tut +object LowerBoundTest extends App { + val empty: ListNode[Null] = ListNode(null, null) + val strList: ListNode[String] = empty.prepend("hello") + .prepend("world") + val anyList: ListNode[Any] = strList.prepend(12345) +} +``` + diff --git a/pl/tutorials/tour/mixin-class-composition.md b/pl/tutorials/tour/mixin-class-composition.md new file mode 100644 index 0000000000..cfe673f398 --- /dev/null +++ b/pl/tutorials/tour/mixin-class-composition.md @@ -0,0 +1,57 @@ +--- +layout: tutorial +title: Kompozycja domieszek + +disqus: true + +tutorial: scala-tour +num: 5 +language: pl +tutorial-next: anonymous-function-syntax +tutorial-previous: traits +--- + +W przeciwieństwie do języków które wspierają jedynie pojedyncze dziedziczenie, Scala posiada bardziej uogólniony mechanizm ponownego wykorzystania klas. Scala umożliwia na wykorzystanie _nowych elementów klasy_ (różnicy w stosunku do klasy bazowej) w definicji nowej klasy. Wyraża się to przy pomocy _kompozycji domieszek_. + +Rozważmy poniższe uogólnienie dla iteratorów: + +```tut +abstract class AbsIterator { + type T + def hasNext: Boolean + def next: T +} +``` + +Następnie, rozważmy klasę domieszkową, która doda do klasy `AbsIterator` metodę `foreach` wykonującą podaną funkcję dla każdego elementu zwracanego przez iterator. Aby zdefiniować klasę domieszkową użyjemy słowa kluczowego `trait`: + +```tut +trait RichIterator extends AbsIterator { + def foreach(f: T => Unit) { while (hasNext) f(next) } +} +``` + +Oto przykład konkretnego iteratora, który zwraca kolejne znaki w podanym łańcuchu znaków: + +```tut +class StringIterator(s: String) extends AbsIterator { + type T = Char + private var i = 0 + def hasNext = i < s.length() + def next = { val ch = s charAt i; i += 1; ch } +} +``` + +Chcielibyśmy także połączyć funkcjonalność `StringIterator` oraz `RichIterator` w jednej klasie. Z pojedynczym dziedziczeniem czy też samymi interfejsami jest to niemożliwe, gdyż obie klasy zawierają implementacje metod. Scala pozwala na rozwiązanie tego problemu z użyciem _kompozycji domieszek_. Umożliwia ona na ponowne wykorzystanie różnicy definicji klas, tzn. wszystkich definicji które nie zostały odziedziczone. Ten mechanizm pozwala nam na połączenie `StringIterator` z `RichIterator`, tak jak w poniższym przykładzie, gdzie chcielibyśmy wypisać w kolumnie wszystkie znaki z danego łańcucha: + +```tut +object StringIteratorTest { + def main(args: Array[String]) { + class Iter extends StringIterator(args(0)) with RichIterator + val iter = new Iter + iter foreach println + } +} +``` + +Klasa `iter` w funkcji `main` jest skonstruowana wykorzystując kompozycję domieszek `StringIterator` oraz `RichIterator` z użyciem słowa kluczowego `with`. Pierwszy rodzic jest nazywany _klasą bazową_ `Iter`, podczas gdy drugi (i każdy kolejny) rodzic jest nazywany _domieszką_. diff --git a/pl/tutorials/tour/named-parameters.md b/pl/tutorials/tour/named-parameters.md new file mode 100644 index 0000000000..31ed29217f --- /dev/null +++ b/pl/tutorials/tour/named-parameters.md @@ -0,0 +1,37 @@ +--- +layout: tutorial +title: Parametry nazwane + +disqus: true + +tutorial: scala-tour +num: 33 +language: pl +tutorial-previous: default-parameter-values +--- + +Wywołując metody i funkcje, możesz użyć nazwy parametru jawnie podczas wywołania: + +```tut + def printName(first:String, last:String) = { + println(first + " " + last) + } + + printName("John", "Smith") + // Wypisuje "John Smith" + printName(first = "John", last = "Smith") + // Wypisuje "John Smith" + printName(last = "Smith", first = "John") + // Wypisuje "John Smith" +``` + +Warto zwrócić uwagę na to, że kolejność wyboru parametrów podczas wywołania nie ma znaczenia, dopóki wszystkie parametry są nazwane. Ta funkcjonalność jest dobrze zintegrowana z [domyślnymi wartościami parametrów](default-parameter-values.html): + +```tut + def printName(first: String = "John", last: String = "Smith") = { + println(first + " " + last) + } + + printName(last = "Jones") + // Wypisuje "John Jones" +``` diff --git a/pl/tutorials/tour/nested-functions.md b/pl/tutorials/tour/nested-functions.md new file mode 100644 index 0000000000..6a94506714 --- /dev/null +++ b/pl/tutorials/tour/nested-functions.md @@ -0,0 +1,35 @@ +--- +layout: tutorial +title: Funkcje zagnieżdżone + +disqus: true + +tutorial: scala-tour +num: 8 +language: pl +tutorial-next: currying +tutorial-previous: higher-order-functions +--- + +Scala pozwala na zagnieżdżanie definicji funkcji. Poniższy obiekt określa funkcję `filter`, która dla danej listy filtruje elementy większe bądź równe niż podany próg `threshold`: + +```tut +object FilterTest extends App { + def filter(xs: List[Int], threshold: Int) = { + def process(ys: List[Int]): List[Int] = + if (ys.isEmpty) ys + else if (ys.head < threshold) ys.head :: process(ys.tail) + else process(ys.tail) + process(xs) + } + println(filter(List(1, 9, 2, 8, 3, 7, 4), 5)) +} +``` + +_Uwaga: zagnieżdżona funkcja `process` odwołuje się do zmiennej `threshold` określonej w zewnętrznym zasięgu jako parametr `filter`_ + +Wynik powyższego programu: + +``` +List(1,2,3,4) +``` diff --git a/pl/tutorials/tour/operators.md b/pl/tutorials/tour/operators.md new file mode 100644 index 0000000000..e999f27a3b --- /dev/null +++ b/pl/tutorials/tour/operators.md @@ -0,0 +1,38 @@ +--- +layout: tutorial +title: Operatory + +disqus: true + +tutorial: scala-tour +num: 29 +language: pl +tutorial-next: automatic-closures +tutorial-previous: local-type-inference +--- + +Każda metoda, która przyjmuje jeden parametr może być użyta jako *operator infiksowy*. Oto definicja klasy `MyBool` która zawiera metody `and` i `or`: + +```tut +case class MyBool(x: Boolean) { + def and(that: MyBool): MyBool = if (x) that else this + def or(that: MyBool): MyBool = if (x) this else that + def negate: MyBool = MyBool(!x) +} +``` + +Można teraz użyć `and` i `or` jako operatory infiksowe: + +```tut +def not(x: MyBool) = x.negate +def xor(x: MyBool, y: MyBool) = (x or y) and not(x and y) +``` + +Można zauważyć, że dzięki zastosowaniu operatorów infiksowych metoda `xor` jest czytelniejsza. + +Dla porównania, oto kod który nie wykorzystuje operatorów infiksowych: + +```tut +def not(x: MyBool) = x.negate +def xor(x: MyBool, y: MyBool) = x.or(y).and(x.and(y).negate) +``` diff --git a/pl/tutorials/tour/pattern-matching.md b/pl/tutorials/tour/pattern-matching.md new file mode 100644 index 0000000000..b4a066c38d --- /dev/null +++ b/pl/tutorials/tour/pattern-matching.md @@ -0,0 +1,45 @@ +--- +layout: tutorial +title: Dopasowanie wzorców (Pattern matching) + +disqus: true + +tutorial: scala-tour +num: 11 +language: pl +tutorial-next: singleton-objects +tutorial-previous: case-classes +--- + +Scala posiada wbudowany mechanizm dopasowania wzorców. Umożliwia on dopasowanie dowolnego rodzaju danych, na podstawie zasady że zwracamy zawsze pierwsze dopasowanie. Przykład dopasowania liczby całkowitej: + +```tut +object MatchTest1 extends App { + def matchTest(x: Int): String = x match { + case 1 => "one" + case 2 => "two" + case _ => "many" + } + println(matchTest(3)) +} +``` + +Blok kodu z wyrażeniami `case` definiuje funkcję, która przekształca liczby całkowite do łańcuchów znaków. Słowo kluczowe `match` pozwala w wygodny sposób zastosować dopasowanie wzorca do obiektu. + +Wzorce można także dopasowywać do różnych typów wartości: + +```tut +object MatchTest2 extends App { + def matchTest(x: Any): Any = x match { + case 1 => "one" + case "two" => 2 + case y: Int => "scala.Int" + } + println(matchTest("two")) +} +``` + +Pierwszy przypadek jest dopasowany, gdy `x` jest liczbą całkowitą równą `1`. Drugi określa przypadek, gdy `x` jest równe łańcuchowi znaków `"two"`. Ostatecznie mamy wzorzec dopasowania typu. Jest on spełniony gdy `x` jest dowolną liczbą całkowitą oraz gwarantuje, że `y` jest (statycznie) typu liczby całkowitej. + +Dopasowanie wzorca w Scali jest najbardziej użyteczne z wykorzystaniem typów algebraicznych modelowanych przez [klasy case](case-classes.html). +Scala także pozwala też na używanie wzorców niezależnie od klas case, używając metody `unapply` definiowanej przez [obiekty ekstraktorów](extractor-objects.html). diff --git a/pl/tutorials/tour/polymorphic-methods.md b/pl/tutorials/tour/polymorphic-methods.md new file mode 100644 index 0000000000..ba662f8b4b --- /dev/null +++ b/pl/tutorials/tour/polymorphic-methods.md @@ -0,0 +1,30 @@ +--- +layout: tutorial +title: Metody polimorficzne + +disqus: true + +tutorial: scala-tour +num: 27 +language: pl +tutorial-next: local-type-inference +tutorial-previous: implicit-conversions +--- + +Metody w Scali mogą być parametryzowane zarówno przez wartości jak i typy. Tak jak na poziomie klas, wartości parametrów zawierają się w parze nawiasów okrągłych, podczas gdy parametry typów są deklarawane w parze nawiasów kwadratowych. + +Przykład poniżej: + +```tut +def dup[T](x: T, n: Int): List[T] = { + if (n == 0) + Nil + else + x :: dup(x, n - 1) +} + +println(dup[Int](3, 4)) +println(dup("three", 3)) +``` + +Metoda `dup` jest sparametryzowana przez typ `T` i parametry wartości `x: T` oraz `n: Int`. W pierwszym wywołaniu `dup` są przekazane wszystkie parametry, ale jak pokazuje kolejna linijka, nie jest wymagane jawne podanie właściwych parametrów typów. System typów w Scali może inferować tego rodzaju typy. Dokonuje się tego poprzez sprawdzenie jakiego typu są parametry dane jako wartości argumentów oraz na podstawie kontekstu wywołania metody. diff --git a/pl/tutorials/tour/regular-expression-patterns.md b/pl/tutorials/tour/regular-expression-patterns.md new file mode 100644 index 0000000000..b8fb8ed6b2 --- /dev/null +++ b/pl/tutorials/tour/regular-expression-patterns.md @@ -0,0 +1,39 @@ +--- +layout: tutorial +title: Wzorce wyrażeń regularnych + +disqus: true + +tutorial: scala-tour +num: 14 +language: pl + +tutorial-next: extractor-objects +tutorial-previous: xml-processing +--- + +## Wzorce sekwencji ignorujące prawą stronę ## + +Wzorce ignorujące prawą stronę są użyteczne przy dekomponowaniu danych, które mogą być podtypem `Seq[A]` lub klasą case z iterowalnym parametrem, jak w poniższym przykładzie: + +``` +Elem(prefix:String, label:String, attrs:MetaData, scp:NamespaceBinding, children:Node*) +``` + +W tych przypadkach, Scala pozwala wzorcom na zastosowanie symbolu `_*` w ostatniej pozycji aby dopasować sekwencje dowolnej długości. +Poniższy przykład demonstruje dopasowanie wzorca, który rozpoznaje początek sekwencji i wiąże resztę do zmiennej `rest`: + +```tut +object RegExpTest1 extends App { + def containsScala(x: String): Boolean = { + val z: Seq[Char] = x + z match { + case Seq('s','c','a','l','a', rest @ _*) => + println("rest is " + rest) + true + case Seq(_*) => + false + } + } +} +``` diff --git a/pl/tutorials/tour/sequence-comprehensions.md b/pl/tutorials/tour/sequence-comprehensions.md new file mode 100644 index 0000000000..32b9d900a7 --- /dev/null +++ b/pl/tutorials/tour/sequence-comprehensions.md @@ -0,0 +1,68 @@ +--- +layout: tutorial +title: Instrukcje for (For comprehension) + +disqus: true + +tutorial: scala-tour +num: 16 +language: pl +tutorial-next: generic-classes +tutorial-previous: extractor-objects +--- + +Scala posiada lekką składnię do wyrażania instrukcji for. Tego typu wyrażania przybierają formę `for (enumerators) yield e`, gdzie `enumerators` oznacza listę enumeratorów oddzielonych średnikami. *Enumerator* może być generatorem wprowadzającym nowe zmienne albo filtrem. Wyrażenie `e` określa wynik dla każdego powiązania wygenerowanego przez enumeratory i zwraca sekwencję tych wartości. + +Przykład: + +```tut +object ComprehensionTest1 extends App { + def even(from: Int, to: Int): List[Int] = + for (i <- List.range(from, to) if i % 2 == 0) yield i + Console.println(even(0, 20)) +} +``` + +To wyrażenie for w funkcji `even` wprowadza nową zmienną `i` typu `Int`, która jest kolejno wiązana ze wszystkimi wartościami listy `List(from, from + 1, ..., to - 1)`. Instrukcja `if i % 2 == 0` filtruje wszystkie liczby nieparzyste, tak aby ciało tego wyrażenia było obliczane tylko dla liczb parzystych. Ostatecznie całe to wyrażenie zwraca listę liczb parzystych. + +Program zwraca następujący wynik: + +``` +List(0, 2, 4, 6, 8, 10, 12, 14, 16, 18) +``` + +Poniżej bardziej skomplikowany przykład, który oblicza wszystkie pary liczb od `0` do `n-1`, których suma jest równa danej wartości `v`: + +```tut +object ComprehensionTest2 extends App { + def foo(n: Int, v: Int) = + for (i <- 0 until n; + j <- i until n if i + j == v) yield + (i, j); + foo(20, 32) foreach { + case (i, j) => + println(s"($i, $j)") + } +} +``` + +Ten przykład pokazuje, że wyrażenia for nie są ograniczone do list. Każdy typ danych, który wspiera operacje: `withFilter`, `map` oraz `flatMap` (z odpowiednimi typami) może być użyty w instrukcjach for. + +Wynik powyższego programu: + +``` +(13, 19) +(14, 18) +(15, 17) +(16, 16) +``` + +Istnieje szczególna postać instrukcji for, które zwracają `Unit`. Tutaj wiązania utworzone przez listę generatorów i filtrów są użyte do wykonania efektów ubocznych. Aby to osiągnąć należy pominąć słowo kluczowe `yield`: + +``` +object ComprehensionTest3 extends App { + for (i <- Iterator.range(0, 20); + j <- Iterator.range(i, 20) if i + j == 32) + println(s"($i, $j)") +} +``` diff --git a/pl/tutorials/tour/singleton-objects.md b/pl/tutorials/tour/singleton-objects.md new file mode 100644 index 0000000000..d7d9381784 --- /dev/null +++ b/pl/tutorials/tour/singleton-objects.md @@ -0,0 +1,70 @@ +--- +layout: tutorial +title: Obiekty singleton + +disqus: true + +tutorial: scala-tour +num: 12 +language: pl + +tutorial-next: xml-processing +tutorial-previous: pattern-matching +--- + +Metody i wartości które nie są powiązane z konkretną instancją [klasy](classes.html) należą do *obiektów singleton*, określanych za pomocą słowa kluczowego `object` zamiast `class`. + +``` +package test + +object Blah { + def sum(l: List[Int]): Int = l.sum +} +``` + +Metoda `sum` jest dostępna globalnie i można się do niej odwołać lub importować jako `test.Blah.sum`. + +Obiekty singleton są swego rodzaju skrótem do definiowania pojedynczej instancji klasy, która nie powinna być bezpośrednio tworzona i która sama w sobie stanowi referencję do tego obiektu, jakby była określona jako `val`. + +Obiekt singleton może rozszerzać klasę lub cechę. Przykładowo [klasa case](case-class.html) bez [parametrów typu](generic-class.html), domyślnie generuje obiekt singleton o tej samej nazwie, który implementuje cechę [`Function*`](http://www.scala-lang.org/api/current/scala/Function1.html). + +## Companion ## + +Duża część obiektów singleton nie istnieje samodzielnie, ale jest powiązana z klasą o tej samej nazwie. Obiekt singleton generowany dla klasy case jest tego przykładem. Kiedy tak się dzieje, obiekt singleton jest zwany *obiektem companion* (co oznacza, że jest _towarzyszem_ tej klasy). + +Klasa i jej obiekt companion mogą być zdefiniowane tylko w tym samym pliku, przykład: + +```tut +class IntPair(val x: Int, val y: Int) + +object IntPair { + import math.Ordering + + implicit def ipord: Ordering[IntPair] = + Ordering.by(ip => (ip.x, ip.y)) +} +``` + +Bardzo powszechne jest użycie wzorca typeclass w połączeniu z [wartościami implicit](implicit-parameters.html), takich jak `ipord` powyżej, zdefiniowanych w obiekcie companion. Dzieje się tak, ponieważ elementy obiektu companion są włączone w procesie wyszukiwania domyślnych wartości implicit. + +## Uwagi dla programistów Javy ## + +`static` nie jest słowem kluczowym w Scali. Zamiast tego, wszyskie elementy, które powinny być statyczne (wliczając w to klasy) powinny zostać zamieszczone w obiekcie singleton. + +Często spotykanym wzorcem jest definiowanie statycznych elementów, np. jako prywatne, pomocniczo dla ich instancji. W Scali przenosi się je do obiektu companion: + +``` +class X { + import X._ + + def blah = foo +} + +object X { + private def foo = 42 +} +``` + +Ten przykład ilustruje inną właściwość Scali: w kontekście zasięgu prywatnego, klasa i jej companion mają wzajemny dostęp do swoich pól. Aby sprawić, że dany element klasy jest *naprawdę* prywatny należy go zadeklarować jako `private[this]`. + +Dla wygodnej współpracy z Javą, metody oraz pola klasy w obiekcie singleton, mają także statyczne metody zdefiniowane w obiekcie companion, nazywane *static forwarder*. Dostęp do innych elementów można uzyskać poprzez statyczne pole `X$.MODULE$` dla obiektu `X`. diff --git a/pl/tutorials/tour/tour-of-scala.md b/pl/tutorials/tour/tour-of-scala.md new file mode 100644 index 0000000000..5fb50d8920 --- /dev/null +++ b/pl/tutorials/tour/tour-of-scala.md @@ -0,0 +1,46 @@ +--- +layout: tutorial +title: Wprowadzenie + +disqus: true + +tutorial: scala-tour +num: 1 +outof: 33 +language: pl +tutorial-next: unified-types +--- + +Scala jest nowoczesnym, wieloparadygmatowym językiem programowania zaprojektowanym do wyrażania powszechnych wzorców programistycznych w zwięzłym, eleganckim i bezpiecznie typowanym stylu. Scala płynnie integruje ze sobą cechy języków funkcyjnych i zorientowanych obiektowo. + +## Scala jest zorientowana obiektowo ## +Scala jest czysto obiektowym językiem w tym sensie, że każda [wartość jest obiektem](unified-types.html). Typy oraz zachowania obiektów są opisane przez [klasy](classes.html) oraz [cechy](traits.html). Klasy są rozszerzane przez podtypowanie i elastyczny mechanizm [kompozycji domieszek](mixin-class-composition.html) jako zastępnik dla wielodziedziczenia. + +## Scala jest funkcyjna ## +Scala jest też funkcyjnym językiem w tym sensie, że [każda funkcja jest wartością](unified-types.html). Scala dostarcza [lekką składnię](anonymous-function-syntax.html) do definiowana funkcji anonimowych, wspiera [funkcje wyższego rzędu](higher-order-functions.html), pozwala funkcjom by były [zagnieżdżone](nested-functions.html) oraz umożliwia [rozwijanie funkcji](currying.html). [Klasy case](case-classes.html) oraz wbudowane wsparcie dla [dopasowania wzorców](pattern-matching.html) wprowadzają do Scali mechanizm typów algebraicznych, stosowany w wielu funkcyjnych językach programowania. [Obiekty singleton](singleton-objects) są wygodną metodą grupowania funkcji, które nie należą do żadnej klasy. + +Ponadto, mechanizm dopasowania wzorca w naturalny sposób rozszerza się do obsługi [przetwarzania danych w formacie XML](xml-processing.html) z pomocą [wzorców sekwencji ignorujących prawą stronę](regular-expression-patterns.html), z wykorzystaniem rozszerzeń [obiektów ekstraktorów](extractor-objects.html). W tym kontekście, [instrukcje for](sequence-comprehensions.html) są użyteczne w formułowaniu zapytań. Ta funkcjonalność sprawia, że Scala jest idealnym językiem do tworzenia aplikacji takich jak usługi sieciowe. + +## Scala jest statycznie typowana ## +Scala posiada ekspresywny system typów, który zapewnia, że abstrakcje są używane w sposób zgodny oraz bezpieczny. W szczególności, system typów wspiera: + +* [klasy generyczne](generic-classes.html) +* [adnotacje wariancji](variances.html) +* [górne](upper-type-bounds.html) oraz [dolne](lower-type-bounds.html) ograniczenia typów +* [klasy zagnieżdżone](inner-classes.html) i [typy abstrakcyjne](abstract-types.html) jako elementy obiektów +* [typy złożone](compound-types.html) +* [jawnie typowane samoreferencje](explicitly-typed-self-references.html) +* [parametry implicit](implicit-parameters.html) i [konwersje](implicit-conversions.html) +* [metody polimorficzne](polymorphic-methods.html) + +[Mechanizm lokalnej inferencji typów](local-type-inference.html) sprawia, że nie jest konieczne podawanie nadmiarowych informacji o typach w programie. W połączeniu, te funkcje języka pozwalają na bezpiecznie typowane ponowne wykorzystanie programistycznych abstrakcji. + +## Scala jest rozszerzalna ## +W praktyce, rozwiązania specyficzne dla domeny wymagają odpowiednich rozszerzeń języka. Scala dostarcza unikalne mechanizmy, dzięki którym można łatwo dodawać nowe konstrukcje do języka w postaci bibliotek: + +* każda metoda może być używana jako [operator infiksowy lub prefiksowy](operators.html) +* [domknięcia są konstruowane automatycznie zależnie od wymaganego typu](automatic-closures.html) + +Powyższe mechanizmy pozwalają na definicję nowych rodzajów wyrażeń, bez potrzeby rozszerzania składni języka czy też wykorzystywania meta-programowania w postaci makr. + +Scala jest zaprojektowana tak, aby współpracować dobrze ze środowiskiem uruchomieniowym JRE oraz językiem Java. Funkcje Javy takie jak [adnotacje](annotations.html) oraz typy generyczne posiadają swoje bezpośrednie odwzorowanie w Scali. Unikalne funkcje Scali, jak na przykład [domyślne wartości parametrów](default-parameter-values.html) oraz [nazwane parametry](named-parameters.html) są kompilowane w taki sposób, aby zachować jak największą zgodność z Javą. Scala ma także taki sam model kompilacji (oddzielna kompilacja, dynamiczne ładowanie klas) dzięki czemu umożliwia korzystanie z całego ekosystemu Javy. diff --git a/pl/tutorials/tour/traits.md b/pl/tutorials/tour/traits.md new file mode 100644 index 0000000000..21d528df7b --- /dev/null +++ b/pl/tutorials/tour/traits.md @@ -0,0 +1,56 @@ +--- +layout: tutorial +title: Cechy + +disqus: true + +tutorial: scala-tour +num: 4 +language: pl +tutorial-next: mixin-class-composition +tutorial-previous: classes +--- + +Zbliżone do interfejsów Javy, cechy są wykorzystywane do definiowania typów obiektów poprzez określenie sygnatur wspieranych metod. Podobnie jak w Javie 8, Scala pozwala cechom na częściową implementację, tzn. jest możliwe podanie domyślnej implementacji dla niektórych metod. W przeciwieństwie do klas, cechy nie mogą posiadać parametrów konstruktora. + +Przykład definicji cechy której zadaniem jest określanie podobieństwa z innym obiektem: + +```tut +trait Similarity { + def isSimilar(x: Any): Boolean + def isNotSimilar(x: Any): Boolean = !isSimilar(x) +} +``` + +Powyższa cecha składa się z dwóch metod: `isSimilar` oraz `isNotSimilar`. Mimo że `isSimilar` nie posiada implementacji (odpowiada metodzie abstrakcyjnej w Javie), `isNotSimilar` definiuje konkretną implementację. W ten sposób klasy które łączą tą cechę, muszą tylko zdefiniować implementacją dla metody `isSimilar`. Zachowanie `isNotSimilar` jest dziedziczone bezpośrednio z tej cechy. Cechy są zazwyczaj łączone z [klasami](classes.html) lub innymi cechami poprzez [kompozycję domieszek](mixin-class-composition.html): + +```tut +class Point(xc: Int, yc: Int) extends Similarity { + var x: Int = xc + var y: Int = yc + def isSimilar(obj: Any) = + obj.isInstanceOf[Point] && + obj.asInstanceOf[Point].x == x +} + +object TraitsTest extends App { + val p1 = new Point(2, 3) + val p2 = new Point(2, 4) + val p3 = new Point(3, 3) + val p4 = new Point(2, 3) + println(p1.isSimilar(p2)) + println(p1.isSimilar(p3)) + // Metoda isNotSimilar jest zdefiniowana w Similarity + println(p1.isNotSimilar(2)) + println(p1.isNotSimilar(p4)) +} +``` + +Wynik działania programu: + +``` +true +false +true +false +``` diff --git a/pl/tutorials/tour/unified-types.md b/pl/tutorials/tour/unified-types.md new file mode 100644 index 0000000000..7b385047ab --- /dev/null +++ b/pl/tutorials/tour/unified-types.md @@ -0,0 +1,48 @@ +--- +layout: tutorial +title: Hierarchia typów + +disqus: true + +tutorial: scala-tour +num: 2 +language: pl +tutorial-next: classes +tutorial-previous: tour-of-scala +--- + +W przeciwieństwie do Javy, wszystkie wartości w Scali są obiektami (wliczając w to wartości numeryczne i funkcje). Ponieważ Scala bazuje na klasach, wszystkie wartości są instancjami klasy. Można zatem powiedzieć, że Scala posiada zunifikowany system typów. Poniższy diagram ilustruje hierarchię klas Scali: + +![Scala Type Hierarchy]({{ site.baseurl }}/resources/images/classhierarchy.img_assist_custom.png) + +## Hierarchia Klas Scali ## + +Klasa bazowa dla wszystkich klas `scala.Any` posiada dwie bezpośrednie klasy pochodne: `scala.AnyVal` oraz `scala.AnyRef`, które reprezentują dwie różne rodziny klas: klasy wartości oraz klasy referencji. Klasy wartości są predefiniowane i odpowiadają one typom prymitywnym z języków takich jak Java. Wszystkie inne klasy definiują typy referencyjne. Klasy zdefiniowane przez użytkownika są domyślnie typami referencyjnymi, tzn. są one zawsze podtypem klasy `scala.AnyRef`. W kontekście maszyny wirtualnej Javy, `scala.AnyRef` odpowiada typowi `java.lang.Object`. Powyższy diagram ilustruje także konwersje implicit pomiędzy klasami wartości. + +Poniższy przykład pokazuje, że liczby, znaki, wartości logiczne oraz funkcje są obiektami: + + +```tut +object UnifiedTypes extends App { + val fun: Int => Int = _ + 1 // deklaracja funkcji + val set = new scala.collection.mutable.LinkedHashSet[Any] + set += "To jest łańcuch znaków" // dodaj łańcuch znaków + set += 732 // dodaj liczbę + set += 'c' // dodaj znak + set += true // dodaj wartość logiczną + set += fun _ // dodaj funkcję + set foreach println +} +``` + +Program deklaruje aplikację `UnifiedTypes` w postaci [obiektu singleton](singleton-objects.html) rozszerzającego klasę `App`. Aplikacja definiuje zmienną lokalną `set` odwołującą się do instancji klasy `LinkedHashSet[Any]`, która reprezentuje zbiór obiektów dowolnego typu (`Any`). Ostatecznie program wypisuje wszystkie elementy tego zbioru. + +Wynik działania programu: + +``` +To jest łańcuch znaków +732 +c +true + +``` diff --git a/pl/tutorials/tour/upper-type-bounds.md b/pl/tutorials/tour/upper-type-bounds.md new file mode 100644 index 0000000000..dc2f604aca --- /dev/null +++ b/pl/tutorials/tour/upper-type-bounds.md @@ -0,0 +1,51 @@ +--- +layout: tutorial +title: Górne ograniczenia typów + +disqus: true + +tutorial: scala-tour +num: 19 +language: pl +tutorial-next: lower-type-bounds +tutorial-previous: variances +--- + +W Scali [parametry typów](generic-classes.html) oraz [typy abstrakcyjne](abstract-types.html) mogą być warunkowane przez ograniczenia typów. Tego rodzaju ograniczenia pomagają określić konkretne wartości zmiennych typu oraz odkryć więcej informacji na temat elementów tych typów. _Ograniczenie górne typu_ `T <: A` zakładają, że zmienna `T` odwołuje się jest podtypem typu `A`. + +Poniższy przykład demonstruje zastosowanie ograniczeń górnych typu dla parametru typu klasy `Cage`: + +```tut +abstract class Animal { + def name: String +} + +abstract class Pet extends Animal {} + +class Cat extends Pet { + override def name: String = "Cat" +} + +class Dog extends Pet { + override def name: String = "Dog" +} + +class Lion extends Animal { + override def name: String = "Lion" +} + +class Cage[P <: Pet](p: P) { + def pet: P = p +} + +object Main extends App { + var dogCage = new Cage[Dog](new Dog) + var catCage = new Cage[Cat](new Cat) + /* Nie można włożyć Lion do Cage, jako że Lion nie jest typu Pet. */ +// var lionCage = new Cage[Lion](new Lion) +} +``` + +Instancja klasy `Cage` może zawierać `Animal` z górnym ograniczeniem `Pet`. Obiekt typu `Lion` nie należy do klasy `Pet` zatem nie może być włożony do obiektu `Cage`. + +Zastosowanie dolnych ograniczeń typów jest opisane [tutaj](lower-type-bounds.html). diff --git a/pl/tutorials/tour/variances.md b/pl/tutorials/tour/variances.md new file mode 100644 index 0000000000..eff2bc87ee --- /dev/null +++ b/pl/tutorials/tour/variances.md @@ -0,0 +1,41 @@ +--- +layout: tutorial +title: Wariancje + +disqus: true + +tutorial: scala-tour +num: 18 +language: pl +tutorial-next: upper-type-bounds +tutorial-previous: generic-classes +--- + +Scala wspiera adnotacje wariancji parametrów typów [klas generycznych](generic-classes.html). W porównaniu do Javy, adnotacje wariancji mogą zostać dodane podczas definiowania abstrakcji klasy, gdy w Javie adnotacje wariancji są podane przez użytkowników tych klas. + +Na stronie o [klasach generycznych](generic-classes.html) omówiliśmy przykład zmiennego stosu. Wyjaśniliśmy, że typ definiowany przez klasę `Stack[T]` jest poddany niezmiennemu podtypowaniu w stosunku do parametru typu. Może to ograniczyć możliwość ponownego wykorzystania abstrakcji tej klasy. Spróbujemy teraz opracować funkcyjną (tzn. immutable) implementację dla stosów, które nie posiadają tego ograniczenia. Warto zwrócić uwagę na to, że jest to zaawansowany przykład łączący w sobie zastosowanie [funkcji polimorficznych](polymorphic-methods.html), [dolnych ograniczeń typu](lower-type-boudns.html) oraz kowariantnych adnotacji parametru typu. Dodatkowo stosujemy też [klasy wewnętrzne](inner-classes.html) aby połączyć ze sobą elementy stosu bez jawnych powiązań. + +```tut +class Stack[+A] { + def push[B >: A](elem: B): Stack[B] = new Stack[B] { + override def top: B = elem + override def pop: Stack[B] = Stack.this + override def toString() = elem.toString() + " " + + Stack.this.toString() + } + def top: A = sys.error("no element on stack") + def pop: Stack[A] = sys.error("no element on stack") + override def toString() = "" +} + +object VariancesTest extends App { + var s: Stack[Any] = new Stack().push("hello"); + s = s.push(new Object()) + s = s.push(7) + println(s) +} +``` + +Adnotacja `+T` określa typ `T` tak, aby mógł być zastosowany wyłącznie w pozycji kowariantnej. Podobnie `-T` deklaruje `T` w taki sposób, że może być użyty tylko w pozycji kontrawariantnej. Dla kowariantnych parametrów typu uzyskujemy kowariantną relację podtypowania w stosunku do tego parametru typu. W naszym przykładzie oznacza to, że `Stack[T]` jest podtypem `Stack[S]` jeżeli `T` jest podtypem `S`. Odwrotnie relacja jest zachowana dla parametrów typu określonych przez `-`. + +Dla przykładu ze stosem chcielibyśmy użyć kowariantnego parametru typu `T` w kontrawariantnej pozycji, aby móc zdefiniować metodę `push`. Ponieważ chcemy uzyskać kowariantne podtypowanie dla stosów, użyjemy sposobu polegającego na abstrahowaniu parametru typu w metodzie `push`. Wynikiem tego jest metoda polimorficzna, w której element typu `T` jest wykorzystany jako ograniczenie dolne zmiennej typu metody `push`. Dzięki temu wariancja parametru `T` staje się zsynchronizowana z jej deklaracją jako typ kowariantny. Teraz stos jest kowariantny, ale nasze rozwiązanie pozwala na przykładowo dodanie łańcucha znaków do stosu liczb całkowitych. Wynikiem takiej operacji będzie stos typu `Stack[Any]`, więc jeżeli ma on być zastosowany w kontekście, gdzie spodziewamy się stosu liczb całkowitych, zostanie wykryty błąd. W innym przypadku uzyskamy stos o bardziej uogólnionym typie elementów. diff --git a/pl/tutorials/tour/xml-processing.md b/pl/tutorials/tour/xml-processing.md new file mode 100644 index 0000000000..a817494214 --- /dev/null +++ b/pl/tutorials/tour/xml-processing.md @@ -0,0 +1,62 @@ +--- +layout: tutorial +title: Przetwarzanie XML + +disqus: true + +tutorial: scala-tour +num: 13 +language: pl +tutorial-next: regular-expression-patterns +tutorial-previous: singleton-objects +--- + +Scala pozwala na łatwe tworzenie, parsowanie oraz przetwarzanie dokumentów w formacie XML. Dane XML mogą być przedstawiane używając generycznych reprezentacji danych lub też z wykorzystaniem specyficznych powiązań za pomocą narzędzia [scalaxb](http://scalaxb.org/). + +Rozważmy następujący dokument XML: + +```html + + + Hello XHTML world + + +

Hello world

+

Scala talks XHTML

+ + +``` + +Ten dokument łatwo można stworzyć pisząc program w Scali: + +```tut +object XMLTest1 extends App { + val page = + + + Hello XHTML world + + +

Hello world

+

Scala talks XHTML

+ + ; + println(page.toString()) +} +``` + +Możliwe jest mieszanie wyrażeń Scali oraz XML: + +```tut +object XMLTest2 extends App { + import scala.xml._ + val df = java.text.DateFormat.getDateInstance() + val dateString = df.format(new java.util.Date()) + def theDate(name: String) = + + Hello, { name }! Today is { dateString } + ; + println(theDate("John Doe").toString()) +} +``` + From 7e5fe32d830f5473af92371202aca3f5bdf67d23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Wy=C5=82uda?= Date: Tue, 10 Jan 2017 12:25:42 +0100 Subject: [PATCH 2/4] Fix example code example in explicitly-typed-self-references.md and several minor corrections --- pl/tutorials/tour/abstract-types.md | 10 +++--- pl/tutorials/tour/annotations.md | 4 +-- .../tour/explicitly-typed-self-references.md | 32 ++++++++++++++----- 3 files changed, 31 insertions(+), 15 deletions(-) diff --git a/pl/tutorials/tour/abstract-types.md b/pl/tutorials/tour/abstract-types.md index ae514cf46f..dcf8dd3ebe 100644 --- a/pl/tutorials/tour/abstract-types.md +++ b/pl/tutorials/tour/abstract-types.md @@ -12,9 +12,9 @@ tutorial-next: compound-types tutorial-previous: inner-classes --- -W Scali, klasy są parametryzowane wartościami (parametry konstruktora) oraz typami (jeżeli klasa jest [generyczna](generic-classes.html)). Aby zachować regularność, zarówno typy jak i wartości są elementami klasy. Analogicznie, mogą być konkretne albo abstrakcyjne. +W Scali, klasy są parametryzowane wartościami (parametry konstruktora) oraz typami (jeżeli klasa jest [generyczna](generic-classes.html)). Aby zachować regularność, zarówno typy jak i wartości są elementami klasy. Analogicznie mogą one być konkretne albo abstrakcyjne. -Poniższy przykład definiuje wartość określaną przez abstrakcyjny typ, będący elementem [cechy](traits.html) `Buffer`: +Poniższy przykład definiuje wartość określaną przez abstrakcyjny typ będący elementem [cechy](traits.html) `Buffer`: ```tut trait Buffer { @@ -23,7 +23,7 @@ trait Buffer { } ``` -*Typy abstrakcyjne* są typami, które nie są jednoznacznie określone. W powyższym przykładzie wiemy tylko, że każdy obiekt klasy `Buffer` posiada typ `T`, ale definicja klasy `Buffer` nie zdradza jakiemu konkretnie typowi odpowiada `T`. Tak jak definicje wartość, możemy także nadpisać definicje typów w klasach pochodnych. Pozwala to nam na odkrywanie dodatkowych informacji o abstrakcyjnym typie poprzez zawężanie jego ograniczeń (które opisują możliwe warianty konkretnego typu). +*Typy abstrakcyjne* są typami, które nie są jednoznacznie określone. W powyższym przykładzie wiemy tylko, że każdy obiekt klasy `Buffer` posiada typ `T`, ale definicja klasy `Buffer` nie zdradza jakiemu konkretnie typowi on odpowiada. Tak jak definicje wartości, możemy także nadpisać definicje typów w klasach pochodnych. Pozwala to nam na odkrywanie dodatkowych informacji o abstrakcyjnym typie poprzez zawężanie jego ograniczeń (które opisują możliwe warianty konkretnego typu). W poniższym programie definiujemy klasę `SeqBuffer`, która ogranicza możliwe typy `T` do pochodnych sekwencji `Seq[U]` dla nowego typu `U`: @@ -35,7 +35,7 @@ abstract class SeqBuffer extends Buffer { } ``` -Cechy oraz [klasy](classes.html) z abstrakcyjnymi typami są często używane w połączeniu z anonimowymi klasami. Aby to zilustrować wykorzystamy program, w którym utworzymy bufor sekwencji, ograniczony do listy liczb całkowitych: +Cechy oraz [klasy](classes.html) z abstrakcyjnymi typami są często używane w połączeniu z anonimowymi klasami. Aby to zilustrować wykorzystamy program, w którym utworzymy bufor sekwencji ograniczony do listy liczb całkowitych: ```tut abstract class IntSeqBuffer extends SeqBuffer { @@ -76,4 +76,4 @@ object AbstractTypeTest2 extends App { } ``` -Należy pamięctać o tym, żeby zastosować [adnotacji wariancji](variance.html). Inaczej nie byłoby możliwe ukrycie konkretnego typu sekwencji obiektu zwracanego przez metodę `newIntSeqBuf`. +Należy też pamiętać o tym, żeby zastosować [adnotacji wariancji](variance.html). Inaczej nie byłoby możliwe ukrycie konkretnego typu sekwencji obiektu zwracanego przez metodę `newIntSeqBuf`. diff --git a/pl/tutorials/tour/annotations.md b/pl/tutorials/tour/annotations.md index 649ae464c2..68b9bcd852 100644 --- a/pl/tutorials/tour/annotations.md +++ b/pl/tutorials/tour/annotations.md @@ -13,11 +13,11 @@ language: pl Adnotacje dodają meta-informacje do różnego rodzaju definicji. -Podstawową formą adnotacji jest `@C` lub `@C(a1, ..., an)`. Tutaj `C` jest konstruktorem klasy `C`, który musi odpowiadać klasie `scala.Annotation`. Wszystkie argumenty konstruktora `a1, ..., an` muszą być stałymi wyrażeniami (czyli wyrażeniami takimi jak liczby, łańcuchy znaków, literały klasowe, enumeracji Javy oraz ich jednowymiarowe tablice). +Podstawową formą adnotacji jest `@C` lub `@C(a1, ..., an)`. Tutaj `C` jest konstruktorem klasy `C`, który musi odpowiadać klasie `scala.Annotation`. Wszystkie argumenty konstruktora `a1, ..., an` muszą być stałymi wyrażeniami (czyli wyrażeniami takimi jak liczby, łańcuchy znaków, literały klasowe, enumeracje Javy oraz ich jednowymiarowe tablice). Adnotację stosuje się do pierwszej definicji lub deklaracji która po niej następuje. Możliwe jest zastosowanie więcej niż jednej adnotacji przed definicją lub deklaracją. Kolejność według której są one określone nie ma istotnego znaczenia. -Znaczenie adnotacji jest zależne od implementacji. Na platformie Java, poniższe adnotacje mają standardowe znaczenie: +Znaczenie adnotacji jest zależne od implementacji. Na platformie Java, poniższe adnotacje domyślnie oznaczają: | Scala | Java | | ------ | ------ | diff --git a/pl/tutorials/tour/explicitly-typed-self-references.md b/pl/tutorials/tour/explicitly-typed-self-references.md index 0f5728f4bc..45b8d800bd 100644 --- a/pl/tutorials/tour/explicitly-typed-self-references.md +++ b/pl/tutorials/tour/explicitly-typed-self-references.md @@ -67,14 +67,30 @@ Jeżeli przyjrzymy się bliżej implementacji metody `connectWith`, możemy dost Scala rozwiązuje ten problem pozwalając na powiązanie klasy z innym typem poprzez jawne typowanie samoreferencji. Możemy użyć tego mechanizmu, aby naprawić powyższy kod: ```tut -class NodeImpl extends NodeIntf { - self: Node => // określenie typu "self" - def connectWith(node: Node): Edge = { - val edge = newEdge(this, node) // w tej chwili się skompiluje - edges = edge :: edges - edge - } -} + abstract class DirectedGraph extends Graph { + type Edge <: EdgeImpl + class EdgeImpl(origin: Node, dest: Node) { + def from = origin + def to = dest + } + class NodeImpl extends NodeIntf { + self: Node => // określenie typu "self" + def connectWith(node: Node): Edge = { + val edge = newEdge(this, node) // w tej chwili się skompiluje + edges = edge :: edges + edge + } + } + protected def newNode: Node + protected def newEdge(from: Node, to: Node): Edge + var nodes: List[Node] = Nil + var edges: List[Edge] = Nil + def addNode: Node = { + val node = newNode + nodes = node :: nodes + node + } + } ``` W nowej definicji klasy `NodeImpl` referencja `this` jest typu `Node`. Ponieważ typ `Node` jest abstrakcyjny i stąd nie wiemy jeszczy, czy `NodeImpl` w rzeczywistości odpowiada `Node`, system typów w Scali nie pozwoli nam na utworzenie tego typu. Mimo wszystko za pomocą jawnej adnotacji typu stwierdzamy, że w pewnym momencie klasa pochodna od `NodeImpl` musi odpowiadać typowi `Node` aby dało się ją utworzyć. From f9b3f6d45704002613ab1540cb5a796f42d892e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Wy=C5=82uda?= Date: Tue, 10 Jan 2017 13:38:06 +0100 Subject: [PATCH 3/4] Fix some typos --- pl/tutorials/tour/abstract-types.md | 2 +- pl/tutorials/tour/annotations.md | 6 +++--- pl/tutorials/tour/automatic-closures.md | 2 +- pl/tutorials/tour/compound-types.md | 2 +- pl/tutorials/tour/default-parameter-values.md | 6 +++--- pl/tutorials/tour/explicitly-typed-self-references.md | 10 +++++----- pl/tutorials/tour/higher-order-functions.md | 4 ++-- pl/tutorials/tour/implicit-conversions.md | 2 +- pl/tutorials/tour/implicit-parameters.md | 4 ++-- pl/tutorials/tour/inner-classes.md | 4 ++-- pl/tutorials/tour/local-type-inference.md | 2 +- pl/tutorials/tour/singleton-objects.md | 2 +- pl/tutorials/tour/variances.md | 2 +- 13 files changed, 24 insertions(+), 24 deletions(-) diff --git a/pl/tutorials/tour/abstract-types.md b/pl/tutorials/tour/abstract-types.md index dcf8dd3ebe..4d58abd20c 100644 --- a/pl/tutorials/tour/abstract-types.md +++ b/pl/tutorials/tour/abstract-types.md @@ -76,4 +76,4 @@ object AbstractTypeTest2 extends App { } ``` -Należy też pamiętać o tym, żeby zastosować [adnotacji wariancji](variance.html). Inaczej nie byłoby możliwe ukrycie konkretnego typu sekwencji obiektu zwracanego przez metodę `newIntSeqBuf`. +Należy też pamiętać o zastosowaniu [adnotacji wariancji](variance.html). Inaczej nie byłoby możliwe ukrycie konkretnego typu sekwencji obiektu zwracanego przez metodę `newIntSeqBuf`. diff --git a/pl/tutorials/tour/annotations.md b/pl/tutorials/tour/annotations.md index 68b9bcd852..230241cd71 100644 --- a/pl/tutorials/tour/annotations.md +++ b/pl/tutorials/tour/annotations.md @@ -36,8 +36,8 @@ Znaczenie adnotacji jest zależne od implementacji. Na platformie Java, poniższ W poniższym przykładzie dodajemy adnotację `throws` do definicji metody `read` w celu obsługi rzuconego wyjątku w programie w Javie. -> Kompilator Javy sprawdza czy program zawiera obsługę dla [wyjątków kontrolowanych](http://docs.oracle.com/javase/tutorial/essential/exceptions/index.html) poprzez sprawdzenie które wyjątki mogą być wynikiem wykonania metody lub konstruktora. Dla każdego kontrolowanego wyjątki który może być wynikiem wykonania, adnotacja **throws** musi określić klasę tego wyjątku lub jedną z jej klas bazowych. -> Ponieważ Scala nie pozwala na definiowanie wyjątków kontrolowanych, jeżeli chcemy móc obsłużyć wyjątek z kodu w Scali w Javie, należy dodać jedną lub więcej adnotacji `throws` określające klasy wyjątek przez nią rzucanych. +> Kompilator Javy sprawdza czy program zawiera obsługę dla [wyjątków kontrolowanych](http://docs.oracle.com/javase/tutorial/essential/exceptions/index.html) poprzez sprawdzenie, które wyjątki mogą być wynikiem wykonania metody lub konstruktora. Dla każdego kontrolowanego wyjątku który może być wynikiem wykonania, adnotacja **throws** musi określić klasę tego wyjątku lub jedną z jej klas bazowych. +> Ponieważ Scala nie pozwala na definiowanie wyjątków kontrolowanych, jeżeli chcemy obsłużyć wyjątek z kodu w Scali w Javie, należy dodać jedną lub więcej adnotacji `throws` określającej klasy wyjątków przez nią rzucanych. ``` package examples @@ -106,7 +106,7 @@ Zastosowanie adnotacji w Scali wygląda podobnie jak wywołanie konstruktora, gd class MyScalaClass ... ``` -Składnia ta może się wydawać nieco nadmiarowa, jeżeli adnotacja składa się tylko z jednego elmentu (bez wartości domyślnej), zatem jeżeli nazwa pola jest określona jako `value`, może być ona stosowana w Javie stosując składnię podobną do konstruktora: +Składnia ta może się wydawać nieco nadmiarowa, jeżeli adnotacja składa się tylko z jednego elementu (bez wartości domyślnej), zatem jeżeli nazwa pola jest określona jako `value`, może być ona stosowana w Javie stosując składnię podobną do konstruktora: ``` @interface SourceURL { diff --git a/pl/tutorials/tour/automatic-closures.md b/pl/tutorials/tour/automatic-closures.md index 26d30abf26..38c7358d96 100644 --- a/pl/tutorials/tour/automatic-closures.md +++ b/pl/tutorials/tour/automatic-closures.md @@ -54,7 +54,7 @@ object TargetTest2 extends App { } ``` -Funkcja `loop` przyjmuje ciało pętli oraz zwraca instancję klasy `LoopUnlessCond` (która enkapsuluje to ciało). Warto zwrócić uwagę, że ciało tej funkcji nie zostało jeszcze ewaluowane. Klasa `LoopUnlessCond` posiada metodę `unless` którą możemy wykorzystać jako *operator infiksowy*. W ten sposób, uzyskaliśmy całkiem naturalną składnię dla naszej nowej pętli: `loop { < stats > } unless ( < cond > )`. +Funkcja `loop` przyjmuje ciało pętli oraz zwraca instancję klasy `LoopUnlessCond` (która enkapsuluje to ciało). Warto zwrócić uwagę, że ciało tej funkcji nie zostało jeszcze ewaluowane. Klasa `LoopUnlessCond` posiada metodę `unless`, którą możemy wykorzystać jako *operator infiksowy*. W ten sposób, uzyskaliśmy całkiem naturalną składnię dla naszej nowej pętli: `loop { < stats > } unless ( < cond > )`. Oto wynik działania programu `TargetTest2`: diff --git a/pl/tutorials/tour/compound-types.md b/pl/tutorials/tour/compound-types.md index b0bedffc5a..c3d90b8484 100644 --- a/pl/tutorials/tour/compound-types.md +++ b/pl/tutorials/tour/compound-types.md @@ -13,7 +13,7 @@ tutorial-previous: abstract-types Czasami konieczne jest wyrażenie, że dany typ jest podtypem kilku innych typów. W Scali wyraża się to za pomocą *typów złożonych*, które są częścią wspólną typów obiektów. -Załóżmy że mamy dwie cechy `Cloneable` i `Resetable`: +Załóżmy, że mamy dwie cechy `Cloneable` i `Resetable`: ```tut trait Cloneable extends java.lang.Cloneable { diff --git a/pl/tutorials/tour/default-parameter-values.md b/pl/tutorials/tour/default-parameter-values.md index 232cc3ea26..23ed9c0d2f 100644 --- a/pl/tutorials/tour/default-parameter-values.md +++ b/pl/tutorials/tour/default-parameter-values.md @@ -11,7 +11,7 @@ tutorial-next: named-parameters tutorial-previous: annotations --- -Scala zezwala na określenie domyślnych wartości dla parametrów co pozwala wyrażeniu wywołującemu ją na pominięcie tych parametrów. +Scala zezwala na określenie domyślnych wartości dla parametrów, co pozwala wyrażeniu wywołującemu ją na pominięcie tych parametrów. W Javie powszechną praktyką jest definiowanie implementacji metod, które służa wyłącznie określeniu domyślnych wartości dla pewnych parametrów dużych metod. Najczęściej stosuje się to w konstruktorach: @@ -30,7 +30,7 @@ public class HashMap { Mamy tutaj do czynienia tylko z dwoma konstruktorami. Pierwszy przyjmuje inną mapę, a drugi wymaga podania pojemności i load factor. Trzeci oraz czwarty konstruktor pozwala użytkownikom `HashMap` na tworzenie instancji z domyślnymi wartościami tych parametrów, które są prawdopodobnie dobre w większości przypadków. -Bardziej problematyczne jest to, że domyślne wartości są zarówno w Javadoc oraz w kodzie. Łatwo można zapomnieć o odpowiedniej aktualizacji tych wartości. Powszechnym wzorcem jest utworzenie publicznych stałych których wartości pojawią się w Javadoc: +Bardziej problematyczne jest to, że domyślne wartości zapisane są zarówno w Javadoc oraz w kodzie. Można łatwo zapomnieć o odpowiedniej aktualizacji tych wartości. Dlatego powszechnym wzorcem jest utworzenie publicznych stałych, których wartości pojawią się w Javadoc: ```java public class HashMap { @@ -53,7 +53,7 @@ Mimo że powstrzymuje to nas od powtarzania się, to podejście nie jest zbyt wy Scala wprowadza bezpośrednie wsparcie dla domyślnych parametrów: ```tut -class HashMap[K,V](initialCapacity:Int = 16, loadFactor:Float = 0.75f) { +class HashMap[K,V](initialCapacity: Int = 16, loadFactor: Float = 0.75f) { } // Używa domyślnych wartości diff --git a/pl/tutorials/tour/explicitly-typed-self-references.md b/pl/tutorials/tour/explicitly-typed-self-references.md index 45b8d800bd..c7ca092432 100644 --- a/pl/tutorials/tour/explicitly-typed-self-references.md +++ b/pl/tutorials/tour/explicitly-typed-self-references.md @@ -28,7 +28,7 @@ abstract class Graph { } ``` -Grafy składają się z listy węzłów oraz krawędzi, gdzie zarówno typ węzłą jak i krawędzi są abstrakcyjne. Użycie [typów abstrakcyjnych](abstract-types.html) pozwala implementacjom cechy `Graph` na to by określały swoje konkretne klasy dla węzłów i krawędzi. Ponadto istnieje tutaj metoda `addNode`, której celem jest dodanie nowych węzłów do grafu. Węzły są połączone z użyciem metody `connectWith`. +Grafy składają się z listy węzłów oraz krawędzi, gdzie zarówno typ węzła jak i krawędzi jest abstrakcyjny. Użycie [typów abstrakcyjnych](abstract-types.html) pozwala implementacjom cechy `Graph` na to, by określały swoje konkretne klasy dla węzłów i krawędzi. Ponadto graf zawiera metodę `addNode`, której celem jest dodanie nowych węzłów do grafu. Węzły są połączone z użyciem metody `connectWith`. Przykład implementacji klasy `Graph`: @@ -62,7 +62,7 @@ Klasa `DirectedGraph` częściowo implementuje i jednocześnie specjalizuje klas Ponieważ konieczne jest udostępnienie możliwości tworzenia wierzchołków i krawędzi w naszej częściowej implementacji grafu, dodane zostały metody fabrykujące `newNode` oraz `newEdge`. Metody `addNode` wraz z `connectWith` są zdefiniowane na podstawie tych metod fabrykujących. -Jeżeli przyjrzymy się bliżej implementacji metody `connectWith`, możemy dostrzec że tworząc krawędź, musimy przekazać samoreferencję `this` do metody fabrykującej `newEdge`. Lecz `this` jest już powązany z typem `NodeImpl`, który nie jest kompatybilny z typem `Node` ponieważ jest on tylko ograniczony z góry typem `NodeImpl`. Wynika z tego, iż powyższy program nie jest prawidłowy i kompilator Scali wyemituje błąd kompilacji. +Jeżeli przyjrzymy się bliżej implementacji metody `connectWith`, możemy dostrzec, że tworząc krawędź, musimy przekazać samoreferencję `this` do metody fabrykującej `newEdge`. Lecz `this` jest już powązany z typem `NodeImpl`, który nie jest kompatybilny z typem `Node`, ponieważ jest on tylko ograniczony z góry typem `NodeImpl`. Wynika z tego, iż powyższy program nie jest prawidłowy i kompilator Scali wyemituje błąd kompilacji. Scala rozwiązuje ten problem pozwalając na powiązanie klasy z innym typem poprzez jawne typowanie samoreferencji. Możemy użyć tego mechanizmu, aby naprawić powyższy kod: @@ -93,9 +93,9 @@ Scala rozwiązuje ten problem pozwalając na powiązanie klasy z innym typem pop } ``` -W nowej definicji klasy `NodeImpl` referencja `this` jest typu `Node`. Ponieważ typ `Node` jest abstrakcyjny i stąd nie wiemy jeszczy, czy `NodeImpl` w rzeczywistości odpowiada `Node`, system typów w Scali nie pozwoli nam na utworzenie tego typu. Mimo wszystko za pomocą jawnej adnotacji typu stwierdzamy, że w pewnym momencie klasa pochodna od `NodeImpl` musi odpowiadać typowi `Node` aby dało się ją utworzyć. +W nowej definicji klasy `NodeImpl` referencja `this` jest typu `Node`. Ponieważ typ `Node` jest abstrakcyjny i stąd nie wiemy jeszcze, czy `NodeImpl` w rzeczywistości odpowiada `Node`, system typów w Scali nie pozwoli nam na utworzenie tego typu. Mimo wszystko za pomocą jawnej adnotacji typu stwierdzamy, że w pewnym momencie klasa pochodna od `NodeImpl` musi odpowiadać typowi `Node`, aby dało się ją utworzyć. -Oto konkretna specjalizacja `DirectedGraph`, gdzie abstrakcyjne elementy klasy mają ustalone konkretne znaczenie: +Oto konkretna specjalizacja `DirectedGraph`, gdzie abstrakcyjne elementy klasy mają ustalone ścisłe znaczenie: ```tut class ConcreteDirectedGraph extends DirectedGraph { @@ -107,7 +107,7 @@ class ConcreteDirectedGraph extends DirectedGraph { } ``` -Należy dodać, że w tej klasie możemy utworzyć `NodeImpl` ponieważ wiemy już teraz, że `NodeImpl` określa klasę pochodną od `Node` (która jest zwyczajnie aliasem dla `NodeImpl`). +Należy dodać, że w tej klasie możemy utworzyć `NodeImpl`, ponieważ wiemy już teraz, że `NodeImpl` określa klasę pochodną od `Node` (która jest po prostu aliasem dla `NodeImpl`). Poniżej przykład zastosowania klasy `ConcreteDirectedGraph`: diff --git a/pl/tutorials/tour/higher-order-functions.md b/pl/tutorials/tour/higher-order-functions.md index f5d5701514..10afa7ec53 100644 --- a/pl/tutorials/tour/higher-order-functions.md +++ b/pl/tutorials/tour/higher-order-functions.md @@ -11,7 +11,7 @@ tutorial-next: nested-functions tutorial-previous: anonymous-function-syntax --- -Scala pozwala na definicję funkcji wyższego rzędu. Są to funkcje, które przyjmują funkcje jako parametry lub których wynik jest też funkcją. Poniżej znajduje się przykład funkcji `apply` który pobiera inną funkcję `f` i wartość `v`, po to by zwrócić wynik zastosowania `f` do `v`: +Scala pozwala na definiowanie funkcji wyższego rzędu. Są to funkcje, które przyjmują funkcje jako parametry lub których wynik jest też funkcją. Poniżej znajduje się przykład funkcji `apply` który pobiera inną funkcję `f` i wartość `v`, po to by zwrócić wynik zastosowania `f` do `v`: ```tut def apply(f: Int => String, v: Int) = f(v) @@ -39,4 +39,4 @@ Wykonanie zwraca poniższy wynik: [7] ``` -W tym przykładzie, metoda `decorator.layout` jest automatycznie konwertowana do funkcji typu `Int => String` czego wymaga funkcja `apply`. Warto dodać, że metoda `decorator.layout` jest polimorficzna, co oznacza, że jej sygnatura jest odpowiednio dopasowana przez kompilator, dzięki czemu gdy jest przekazana do funkcji `apply`, jest ona traktowana jako `Int => String`. +W tym przykładzie, metoda `decorator.layout` jest automatycznie konwertowana do funkcji typu `Int => String`, czego wymaga funkcja `apply`. Warto dodać, że metoda `decorator.layout` jest polimorficzna, co oznacza, że jej sygnatura jest odpowiednio dopasowana przez kompilator, dzięki czemu gdy jest przekazana do funkcji `apply`, jest ona traktowana jako `Int => String`. diff --git a/pl/tutorials/tour/implicit-conversions.md b/pl/tutorials/tour/implicit-conversions.md index 84f20f9ac0..79d2353cf7 100644 --- a/pl/tutorials/tour/implicit-conversions.md +++ b/pl/tutorials/tour/implicit-conversions.md @@ -19,7 +19,7 @@ Konwersje implicit są stosowane w dwóch sytuacjach: * W przypadku wyboru `e.m` z `e` typu `T`, jeżeli `m` nie jest elementem `T`. W pierwszym przypadku wyszukiwana jest konwersja `c`, którą można zastosować do `e` aby uzyskać wynik typu `T`. -W drugim przypadku wyszukiwana jest konwersja `c`, którą można zastosować do `e` i której wyniki zawiera element nazwany `m`. +W drugim przypadku wyszukiwana jest konwersja `c`, którą można zastosować do `e` i której wynik zawiera element nazwany `m`. Poniższa operacja na dwóch listach `xs` oraz `ys` typu `List[Int]` jest dopuszczalna: diff --git a/pl/tutorials/tour/implicit-parameters.md b/pl/tutorials/tour/implicit-parameters.md index 08d3ad454b..276ac9eb38 100644 --- a/pl/tutorials/tour/implicit-parameters.md +++ b/pl/tutorials/tour/implicit-parameters.md @@ -11,7 +11,7 @@ tutorial-next: implicit-conversions tutorial-previous: explicitly-typed-self-references --- -Metodę z _parametrami implicit_ można stosować tak samo jak zwyczajną metod. W takim przypadku etykieta `implicit` nie ma żadnego znaczenia. Jednak jeżeli odpowiednie argumenty dla parametrów implicit nie zostaną jawnie określone, to kompilator dostarczy je automatycznie. +Metodę z _parametrami implicit_ można stosować tak samo jak zwyczajną metodę. W takim przypadku etykieta `implicit` nie ma żadnego znaczenia. Jednak jeżeli odpowiednie argumenty dla parametrów implicit nie zostaną jawnie określone, to kompilator dostarczy je automatycznie. Argumenty które mogą być przekazywane jako parametry implicit można podzielić na dwie kategorie: @@ -39,7 +39,7 @@ object ImplicitTest extends App { def add(x: Int, y: Int): Int = x + y def unit: Int = 0 } - /** Metoda sum pobiera List[A] i zwraca A, który jest wynikiem zastosowania zastosowania monoidu do wszystkich kolejnych elementów listy. Oznaczając parametr m jako implicit sprawiamy, że potrzebne jest tylko podanie parametru xs podczas wywołania, ponieważ mamy już List[A], zatem wiemy jakiego typue jest w rzeczywistości A, zatem wiemy też jakiego typu Monoid[A] jest potrzebny. Możemy więc wyszukać wartość val lub obiekt w aktualnym zasięgu, który ma odpowiadający typu i użyć go bez jawnego określania referencji do niego. */ + /** Metoda sum pobiera List[A] i zwraca A, który jest wynikiem zastosowania zastosowania monoidu do wszystkich kolejnych elementów listy. Oznaczając parametr m jako implicit sprawiamy, że potrzebne jest tylko podanie parametru xs podczas wywołania, ponieważ mamy już List[A], zatem wiemy jakiego typu jest w rzeczywistości A, zatem wiemy też jakiego typu Monoid[A] jest potrzebny. Możemy więc wyszukać wartość val lub obiekt w aktualnym zasięgu, który ma odpowiadający typu i użyć go bez jawnego określania referencji do niego. */ def sum[A](xs: List[A])(implicit m: Monoid[A]): A = if (xs.isEmpty) m.unit else m.add(xs.head, sum(xs.tail)) diff --git a/pl/tutorials/tour/inner-classes.md b/pl/tutorials/tour/inner-classes.md index 5b711f283a..a04d08a35d 100644 --- a/pl/tutorials/tour/inner-classes.md +++ b/pl/tutorials/tour/inner-classes.md @@ -45,7 +45,7 @@ object GraphTest extends App { } ``` -Teraz wzbogacimy nasz przykład o jawne typowanie aby można było zobaczyć powiązanie typów wierzchołków z grafem: +Teraz wzbogacimy nasz przykład o jawne typowanie, aby można było zobaczyć powiązanie typów wierzchołków z grafem: ```tut object GraphTest extends App { @@ -74,7 +74,7 @@ object IllegalGraphTest extends App { } ``` -Warto zwrócić uwagę na to, że ostatnia linia poprzedniego przykłady byłaby poprawnym programem w Javie. Dla wierzchołków obu grafów Java przypisałaby ten sam typ `Graph.Node`. W Scali także istnieje możliwość wyrażenia takiego typu, zapisując go w formie: `Graph#Node`. Jeżeli byśmy chcieli połączyć wierzchołki różnych grafów, musielibyśmy wtedy zmienić definicję implementacji naszego grafu w następujący sposób: +Warto zwrócić uwagę na to, że ostatnia linia poprzedniego przykładu byłaby poprawnym programem w Javie. Dla wierzchołków obu grafów Java przypisałaby ten sam typ `Graph.Node`. W Scali także istnieje możliwość wyrażenia takiego typu, zapisując go w formie: `Graph#Node`. Jeżeli byśmy chcieli połączyć wierzchołki różnych grafów, musielibyśmy wtedy zmienić definicję implementacji naszego grafu w następujący sposób: ```tut class Graph { diff --git a/pl/tutorials/tour/local-type-inference.md b/pl/tutorials/tour/local-type-inference.md index c76d2551e1..6cb61a7914 100644 --- a/pl/tutorials/tour/local-type-inference.md +++ b/pl/tutorials/tour/local-type-inference.md @@ -31,7 +31,7 @@ object InferenceTest2 { } ``` -Nie jest też konieczne określenie parametrów typu, kiedy są wywoływanie [metody polimorficzne](polymorphic-methods.html) lub kiedy tworzymy [klasy generyczne](generic-classes.html). Kompilator Scali sam określi typ brakujących parametrów typów na podstawie kontekstu oraz typów właściwych parametrów metody/konstruktora. +Nie jest też konieczne określenie parametrów typu, kiedy są wywoływane [metody polimorficzne](polymorphic-methods.html) lub kiedy tworzymy [klasy generyczne](generic-classes.html). Kompilator Scali sam określi typ brakujących parametrów typów na podstawie kontekstu oraz typów właściwych parametrów metody/konstruktora. Oto przykład który to ilustruje: diff --git a/pl/tutorials/tour/singleton-objects.md b/pl/tutorials/tour/singleton-objects.md index d7d9381784..b1696b689e 100644 --- a/pl/tutorials/tour/singleton-objects.md +++ b/pl/tutorials/tour/singleton-objects.md @@ -49,7 +49,7 @@ Bardzo powszechne jest użycie wzorca typeclass w połączeniu z [wartościami i ## Uwagi dla programistów Javy ## -`static` nie jest słowem kluczowym w Scali. Zamiast tego, wszyskie elementy, które powinny być statyczne (wliczając w to klasy) powinny zostać zamieszczone w obiekcie singleton. +`static` nie jest słowem kluczowym w Scali. Zamiast tego, wszystkie elementy, które powinny być statyczne (wliczając w to klasy) powinny zostać zamieszczone w obiekcie singleton. Często spotykanym wzorcem jest definiowanie statycznych elementów, np. jako prywatne, pomocniczo dla ich instancji. W Scali przenosi się je do obiektu companion: diff --git a/pl/tutorials/tour/variances.md b/pl/tutorials/tour/variances.md index eff2bc87ee..6224a26200 100644 --- a/pl/tutorials/tour/variances.md +++ b/pl/tutorials/tour/variances.md @@ -13,7 +13,7 @@ tutorial-previous: generic-classes Scala wspiera adnotacje wariancji parametrów typów [klas generycznych](generic-classes.html). W porównaniu do Javy, adnotacje wariancji mogą zostać dodane podczas definiowania abstrakcji klasy, gdy w Javie adnotacje wariancji są podane przez użytkowników tych klas. -Na stronie o [klasach generycznych](generic-classes.html) omówiliśmy przykład zmiennego stosu. Wyjaśniliśmy, że typ definiowany przez klasę `Stack[T]` jest poddany niezmiennemu podtypowaniu w stosunku do parametru typu. Może to ograniczyć możliwość ponownego wykorzystania abstrakcji tej klasy. Spróbujemy teraz opracować funkcyjną (tzn. immutable) implementację dla stosów, które nie posiadają tego ograniczenia. Warto zwrócić uwagę na to, że jest to zaawansowany przykład łączący w sobie zastosowanie [funkcji polimorficznych](polymorphic-methods.html), [dolnych ograniczeń typu](lower-type-boudns.html) oraz kowariantnych adnotacji parametru typu. Dodatkowo stosujemy też [klasy wewnętrzne](inner-classes.html) aby połączyć ze sobą elementy stosu bez jawnych powiązań. +Na stronie o [klasach generycznych](generic-classes.html) omówiliśmy przykład zmiennego stosu. Wyjaśniliśmy, że typ definiowany przez klasę `Stack[T]` jest poddany niezmiennemu podtypowaniu w stosunku do parametru typu. Może to ograniczyć możliwość ponownego wykorzystania abstrakcji tej klasy. Spróbujemy teraz opracować funkcyjną (tzn. immutable) implementację dla stosów, które nie posiadają tego ograniczenia. Warto zwrócić uwagę na to, że jest to zaawansowany przykład łączący w sobie zastosowanie [funkcji polimorficznych](polymorphic-methods.html), [dolnych ograniczeń typu](lower-type-bounds.html) oraz kowariantnych adnotacji parametru typu. Dodatkowo stosujemy też [klasy wewnętrzne](inner-classes.html), aby połączyć ze sobą elementy stosu bez jawnych powiązań. ```tut class Stack[+A] { From 1ec6c96e62c999d7433d64f68dcc8f053facf84f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Wy=C5=82uda?= Date: Wed, 11 Jan 2017 17:50:18 +0100 Subject: [PATCH 4/4] Add improvements to the translation --- pl/tutorials/tour/case-classes.md | 22 +++++++++---------- pl/tutorials/tour/extractor-objects.md | 2 +- pl/tutorials/tour/generic-classes.md | 2 +- pl/tutorials/tour/implicit-conversions.md | 14 ++++++------ pl/tutorials/tour/implicit-parameters.md | 20 ++++++++--------- pl/tutorials/tour/inner-classes.md | 2 +- pl/tutorials/tour/lower-type-bounds.md | 2 +- pl/tutorials/tour/nested-functions.md | 2 +- pl/tutorials/tour/pattern-matching.md | 6 ++--- .../tour/regular-expression-patterns.md | 2 +- pl/tutorials/tour/singleton-objects.md | 16 +++++++------- pl/tutorials/tour/tour-of-scala.md | 4 ++-- pl/tutorials/tour/upper-type-bounds.md | 2 +- pl/tutorials/tour/variances.md | 2 +- 14 files changed, 49 insertions(+), 49 deletions(-) diff --git a/pl/tutorials/tour/case-classes.md b/pl/tutorials/tour/case-classes.md index 92f546c5d4..998fa6022d 100644 --- a/pl/tutorials/tour/case-classes.md +++ b/pl/tutorials/tour/case-classes.md @@ -1,6 +1,6 @@ --- layout: tutorial -title: Klasy case +title: Klasy przypadków disqus: true @@ -11,14 +11,14 @@ tutorial-next: pattern-matching tutorial-previous: currying --- -Scala wspiera mechanizm _klas case_. Klasy case są zwykłymi klasami z dodatkowymi założeniami: +Scala wspiera mechanizm _klas przypadków_. Klasy przypadków są zwykłymi klasami z dodatkowymi założeniami: -* Domyślnie immutable +* Domyślnie niemutowalne * Można je dekomponować poprzez [dopasowanie wzorca](pattern-matching.html) * Porównywane poprzez podobieństwo strukturalne zamiast przez referencje * Zwięzła składnia tworzenia obiektów i operacji na nich -Poniższy przykład obrazuje hierarchię typów powiadomień, która składa się z abstrakcyjnej klasy `Notification` oraz trzech konkretnych rodzajów zaimplementowanych jako klasy case `Email`, `SMS` i `VoiceRecording`: +Poniższy przykład obrazuje hierarchię typów powiadomień, która składa się z abstrakcyjnej klasy `Notification` oraz trzech konkretnych rodzajów zaimplementowanych jako klasy przypadków `Email`, `SMS` i `VoiceRecording`: ```tut abstract class Notification @@ -33,17 +33,17 @@ Tworzenie obiektu jest bardzo proste: (Zwróć uwagę na to, że słowo `new` n val emailFromJohn = Email("john.doe@mail.com", "Greetings From John!", "Hello World!") ``` -Parametry konstruktora klasy case są traktowane jako publiczne wartości i można się do nich odwoływać bezpośrednio: +Parametry konstruktora klasy przypadków są traktowane jako publiczne wartości i można się do nich odwoływać bezpośrednio: ```tut val title = emailFromJohn.title println(title) // wypisuje "Greetings From John!" ``` -W klasach case nie można modyfikować wartości pól. (Z wyjątkiem sytuacji kiedy dodasz `var` przed nazwą pola) +W klasach przypadków nie można modyfikować wartości pól. (Z wyjątkiem sytuacji kiedy dodasz `var` przed nazwą pola) ```tut:fail -emailFromJohn.title = "Goodbye From John!" // Jest to błąd kompilacji, gdyż pola klasy case są domyślnie immutable +emailFromJohn.title = "Goodbye From John!" // Jest to błąd kompilacji, gdyż pola klasy przypadku są domyślnie niezmienne ``` Zamiast tego, możesz utworzyć kopię używając metody `copy`: @@ -55,7 +55,7 @@ println(emailFromJohn) // wypisuje "Email(john.doe@mail.com,Greetings From John! println(editedEmail) // wypisuje "Email(john.doe@mail.com,I am learning Scala,It's so cool!)" ``` -Dla każdej klasy case kompilator Scali generuje metodę `equals`, która implementuje strukturalne porównanie obiektów oraz metodę `toString`. Przykład: +Dla każdej klasy przypadku kompilator Scali wygeneruje metodę `equals`, która implementuje strukturalne porównanie obiektów oraz metodę `toString`. Przykład: ```tut val firstSms = SMS("12345", "Hello!") @@ -75,7 +75,7 @@ They are equal! SMS is: SMS(12345, Hello!) ``` -Jednym z najważniejszych zastosowań klas case (skąd też się wzięła ich nazwa), jest **dopasowanie wzorca**. Poniższy przykład pokazuje działanie funkcji, która zwraca różne komunikaty, w zależności od rodzaju powiadomienia: +Jednym z najważniejszych zastosowań klas przypadków (skąd też się wzięła ich nazwa), jest **dopasowanie wzorca**. Poniższy przykład pokazuje działanie funkcji, która zwraca różne komunikaty, w zależności od rodzaju powiadomienia: ```tut def showNotification(notification: Notification): String = { @@ -134,9 +134,9 @@ println(showNotificationSpecial(specialSms, SPECIAL_EMAIL, SPECIAL_NUMBER)) ``` -Programując w Scali, zachęca się abyś jak najszerzej używał klas case do modelowania danych, jako że kod który je wykorzystuje jest bardziej ekspresywny i łatwiejszy do utrzymania: +Programując w Scali, zachęca się abyś jak najszerzej używał klas przypadków do modelowania danych, jako że kod który je wykorzystuje jest bardziej ekspresywny i łatwiejszy do utrzymania: -* Obiekty typu immutable uwalniają cię od potrzeby śledzenia zmian stanu +* Obiekty niemutowalne uwalniają cię od potrzeby śledzenia zmian stanu * Porównanie przez wartość pozwala na porównywanie instancji tak jakby były prymitywnymi wartościami * Dopasowanie wzorca znacząco upraszcza logikę rozgałęzień, co prowadzi do mniejszej ilości błędów i czytelniejszego kodu diff --git a/pl/tutorials/tour/extractor-objects.md b/pl/tutorials/tour/extractor-objects.md index 72a68ae0f7..3f100ca99d 100644 --- a/pl/tutorials/tour/extractor-objects.md +++ b/pl/tutorials/tour/extractor-objects.md @@ -11,7 +11,7 @@ tutorial-next: sequence-comprehensions tutorial-previous: regular-expression-patterns --- -W Scali, wzorce mogą być zdefiniowane niezależnie od klas case. Obiekt posiadający metodę `unapply` może funkcjonować jako tak zwany ekstraktor. Jest to szczególna metoda, która pozwala na odwrócenie zastosowania obiektu dla pewnych danych. Jego celem jest ekstrakcja danych, z których został on utworzony. Dla przykładu, poniższy kod definiuje ekstraktor dla [obiektu](singleton-objects.html) `Twice`: +W Scali, wzorce mogą być zdefiniowane niezależnie od klas przypadków. Obiekt posiadający metodę `unapply` może funkcjonować jako tak zwany ekstraktor. Jest to szczególna metoda, która pozwala na odwrócenie zastosowania obiektu dla pewnych danych. Jego celem jest ekstrakcja danych, z których został on utworzony. Dla przykładu, poniższy kod definiuje ekstraktor dla [obiektu](singleton-objects.html) `Twice`: ```tut object Twice { diff --git a/pl/tutorials/tour/generic-classes.md b/pl/tutorials/tour/generic-classes.md index a4502cdc55..e17a1374ac 100644 --- a/pl/tutorials/tour/generic-classes.md +++ b/pl/tutorials/tour/generic-classes.md @@ -24,7 +24,7 @@ class Stack[T] { } ``` -Klasa `Stack` modeluje zmienny stos z zawierający elementy dowolnego typu `T`. Parametr `T` narzuca ograniczenie dla metod takie, że tylko elementy typu `T` mogą zostać dodane do stosu. Podobnie metoda `top` może zwrócić tylko elementy danego typu. +Klasa `Stack` modeluje zmienny stos zawierający elementy dowolnego typu `T`. Parametr `T` narzuca ograniczenie dla metod takie, że tylko elementy typu `T` mogą zostać dodane do stosu. Podobnie metoda `top` może zwrócić tylko elementy danego typu. Przykłady zastosowania: diff --git a/pl/tutorials/tour/implicit-conversions.md b/pl/tutorials/tour/implicit-conversions.md index 79d2353cf7..bf37ba5805 100644 --- a/pl/tutorials/tour/implicit-conversions.md +++ b/pl/tutorials/tour/implicit-conversions.md @@ -1,6 +1,6 @@ --- layout: tutorial -title: Konwersje implicit +title: Konwersje niejawne disqus: true @@ -11,9 +11,9 @@ tutorial-next: polymorphic-methods tutorial-previous: implicit-parameters --- -Konwersja implicit z typu `S` do `T` jest określona przez wartość implicit, która jest funkcją typu `S => T` lub przez metodę implicit odpowiadającą funkcji tego typu. +Konwersja niejawna z typu `S` do `T` jest określona przez wartość domniemaną, która jest funkcją typu `S => T` lub przez metodę domniemaną odpowiadającą funkcji tego typu. -Konwersje implicit są stosowane w dwóch sytuacjach: +Konwersje niejawne mogą być są zastosowane w jednej z dwóch sytuacji: * Jeżeli wyrażenie `e` jest typu `S` i `S` nie odpowiada wymaganemu typowi `T`. * W przypadku wyboru `e.m` z `e` typu `T`, jeżeli `m` nie jest elementem `T`. @@ -27,7 +27,7 @@ Poniższa operacja na dwóch listach `xs` oraz `ys` typu `List[Int]` jest dopusz xs <= ys ``` -Zakładając, że metody implicit `list2ordered` oraz `int2ordered` zdefiniowane poniżej znajdują się w danym zakresie: +Zakładając, że metody niejawne `list2ordered` oraz `int2ordered` zdefiniowane poniżej znajdują się w danym zakresie: ``` implicit def list2ordered[A](x: List[A]) @@ -38,9 +38,9 @@ implicit def int2ordered(x: Int): Ordered[Int] = new Ordered[Int] { /* .. */ } ``` -Domyślnie importowany obiekt `scala.Predef` deklaruje kilka predefiniowanych typów (np. `Pair`) i metod (np. `assert`) ale także wiele użytecznych konwersji implicit. +Domyślnie importowany obiekt `scala.Predef` deklaruje kilka predefiniowanych typów (np. `Pair`) i metod (np. `assert`) ale także wiele użytecznych konwersji niejawnych. -Przykładowo, kiedy wywołujemy metodę Javy, która wymaga typu `java.lang.Integer`, dopuszczalne jest przekazanie typu `scala.Int`. Dzieje się tak ponieważ `Predef` zawiera poniższe konwersje implicit: +Przykładowo, kiedy wywołujemy metodę Javy, która wymaga typu `java.lang.Integer`, dopuszczalne jest przekazanie typu `scala.Int`. Dzieje się tak ponieważ `Predef` definiuje poniższe konwersje niejawne: ```tut import scala.language.implicitConversions @@ -49,4 +49,4 @@ implicit def int2Integer(x: Int) = java.lang.Integer.valueOf(x) ``` -Aby zdefiniować własne konwersje implicit, należy zaimportować `scala.language.implicitConversions` (albo uruchomić kompilator z opcją `-language:implicitConversions`). Ta funkcjonalność musi być włączona jawnie, ze względu na problemy jakie mogą się wiązać z ich nadmiernym stosowaniem. +Aby zdefiniować własne konwersje niejawne, należy zaimportować `scala.language.implicitConversions` (albo uruchomić kompilator z opcją `-language:implicitConversions`). Ta funkcjonalność musi być włączona jawnie, ze względu na problemy jakie mogą się wiązać z ich nadmiernym stosowaniem. diff --git a/pl/tutorials/tour/implicit-parameters.md b/pl/tutorials/tour/implicit-parameters.md index 276ac9eb38..e64d460041 100644 --- a/pl/tutorials/tour/implicit-parameters.md +++ b/pl/tutorials/tour/implicit-parameters.md @@ -1,6 +1,6 @@ --- layout: tutorial -title: Parametry implicit +title: Parametry domniemane disqus: true @@ -11,17 +11,17 @@ tutorial-next: implicit-conversions tutorial-previous: explicitly-typed-self-references --- -Metodę z _parametrami implicit_ można stosować tak samo jak zwyczajną metodę. W takim przypadku etykieta `implicit` nie ma żadnego znaczenia. Jednak jeżeli odpowiednie argumenty dla parametrów implicit nie zostaną jawnie określone, to kompilator dostarczy je automatycznie. +Metodę z _parametrami domniemanymi_ można stosować tak samo jak każdą zwyczajną metodę. W takim przypadku etykieta `implicit` nie ma żadnego znaczenia. Jednak jeżeli odpowiednie argumenty dla parametrów domniemanych nie zostaną jawnie określone, to kompilator dostarczy je automatycznie. -Argumenty które mogą być przekazywane jako parametry implicit można podzielić na dwie kategorie: +Argumenty które mogą być przekazywane jako parametry domniemane można podzielić na dwie kategorie: -* Najpierw dobierane są takie identyfikatory, które są dostępne bezpośrednio w punkcie wywołania metody i które określają definicję lub parametr implicit. -* W drugiej kolejności dobrane mogą być elementy modułów companion odpowiadających typom tych parametrów implicit, które są oznaczone jako `implicit`. +* Najpierw dobierane są takie identyfikatory, które są dostępne bezpośrednio w punkcie wywołania metody i które określają definicję lub parametr domniemany. +* W drugiej kolejności dobrane mogą być elementy modułów towarzyszących odpowiadających typom tych parametrów domniemanych, które są oznaczone jako `implicit`. -W poniższym przykładzie zdefiniujemy metodę `sum`, która oblicza sumę listy elementów wykorzystując operacje `add` i `unit` obiektu `Monoid`. Należy dodać, że wartości implicit nie mogą być zdefiniowane globalnie, tylko muszą być elementem pewnego modułu. +W poniższym przykładzie zdefiniujemy metodę `sum`, która oblicza sumę listy elementów wykorzystując operacje `add` i `unit` obiektu `Monoid`. Należy dodać, że wartości domniemane nie mogą być zdefiniowane globalnie, tylko muszą być elementem pewnego modułu. ```tut -/** Ten przykład wykorzystuje strukturę z algebry abstrakcyjnej aby zilustrować działanie parametrów implicit. Półgrupa jest strukturą algebraiczną na zbiorze A z łączna (która spełnia warunek: add(x, add(y, z)) == add(add(x, y), z)) operacją nazwaną add, która łączy parę obiektów A by zwrócić inny A. */ +/** Ten przykład wykorzystuje strukturę z algebry abstrakcyjnej aby zilustrować działanie parametrów domniemanych. Półgrupa jest strukturą algebraiczną na zbiorze A z łączną operacją (czyli taką, która spełnia warunek: add(x, add(y, z)) == add(add(x, y), z)) nazwaną add, która łączy parę obiektów A by zwrócić inny obiekt A. */ abstract class SemiGroup[A] { def add(x: A, y: A): A } @@ -30,7 +30,7 @@ abstract class Monoid[A] extends SemiGroup[A] { def unit: A } object ImplicitTest extends App { - /** Aby zademonstrować jak działają parametry implicit, najpierw zdefiniujemy monoidy dla łańcuchów znaków oraz liczb całkowitych. Słowo kluczowe implicit sprawia, że oznaczone nimi wartości mogą być użyte aby zrealizować parametry implicit. */ + /** Aby zademonstrować jak działają parametry domniemane, najpierw zdefiniujemy monoidy dla łańcuchów znaków oraz liczb całkowitych. Słowo kluczowe implicit sprawia, że oznaczone nimi wartości mogą być użyte aby zrealizować parametry domniemane. */ implicit object StringMonoid extends Monoid[String] { def add(x: String, y: String): String = x concat y def unit: String = "" @@ -39,12 +39,12 @@ object ImplicitTest extends App { def add(x: Int, y: Int): Int = x + y def unit: Int = 0 } - /** Metoda sum pobiera List[A] i zwraca A, który jest wynikiem zastosowania zastosowania monoidu do wszystkich kolejnych elementów listy. Oznaczając parametr m jako implicit sprawiamy, że potrzebne jest tylko podanie parametru xs podczas wywołania, ponieważ mamy już List[A], zatem wiemy jakiego typu jest w rzeczywistości A, zatem wiemy też jakiego typu Monoid[A] jest potrzebny. Możemy więc wyszukać wartość val lub obiekt w aktualnym zasięgu, który ma odpowiadający typu i użyć go bez jawnego określania referencji do niego. */ + /** Metoda sum pobiera List[A] i zwraca A, który jest wynikiem zastosowania monoidu do wszystkich kolejnych elementów listy. Oznaczając parametr m jako domniemany, sprawiamy że potrzebne jest tylko podanie parametru xs podczas wywołania, ponieważ mamy już List[A], zatem wiemy jakiego typu jest w rzeczywistości A, zatem wiemy też jakiego typu Monoid[A] potrzebujemy. Możemy więc wyszukać wartość val lub obiekt w aktualnym zasięgu, który ma odpowiadający typu i użyć go bez jawnego określania referencji do niego. */ def sum[A](xs: List[A])(implicit m: Monoid[A]): A = if (xs.isEmpty) m.unit else m.add(xs.head, sum(xs.tail)) - /** Wywołamy tutaj dwa razy sum, podając za każdym razem tylko listę. Ponieważ drugi parametr (m) jest implicit, jego wartość jest wyszukiwana przez kompilator w aktualnym zasięgu, na podstawie typu monoidu wymaganego w każdym przypadku, co oznacza że oba wyrażenia mogą być w pełni ewaluowane. */ + /** Wywołamy tutaj dwa razy sum, podając za każdym razem tylko listę. Ponieważ drugi parametr (m) jest domniemany, jego wartość jest wyszukiwana przez kompilator w aktualnym zasięgu, na podstawie typu monoidu wymaganego w każdym przypadku, co oznacza że oba wyrażenia mogą być w pełni ewaluowane. */ println(sum(List(1, 2, 3))) // używa IntMonoid println(sum(List("a", "b", "c"))) // używa StringMonoid } diff --git a/pl/tutorials/tour/inner-classes.md b/pl/tutorials/tour/inner-classes.md index a04d08a35d..034191715c 100644 --- a/pl/tutorials/tour/inner-classes.md +++ b/pl/tutorials/tour/inner-classes.md @@ -58,7 +58,7 @@ object GraphTest extends App { } ``` -Ten kod pokazuje, że typ wierzchołka jest prefikowany przez swoją zewnętrzną instancję (która jest obiektem `g` w naszym przykładzie). Jeżeli mielibyśmy dwa grafy, system typów w Scali nie pozwoli nam na pomieszanie wierzchołków jednego z wierzchołkami drugiego, ponieważ wierzchołki innego grafu są określone innym przez inny typ. +Ten kod pokazuje, że typ wierzchołka jest prefiksowany przez swoją zewnętrzną instancję (która jest obiektem `g` w naszym przykładzie). Jeżeli mielibyśmy dwa grafy, system typów w Scali nie pozwoli nam na pomieszanie wierzchołków jednego z wierzchołkami drugiego, ponieważ wierzchołki drugiego grafu są określone przez inny typ. Przykład niedopuszczalnego programu: diff --git a/pl/tutorials/tour/lower-type-bounds.md b/pl/tutorials/tour/lower-type-bounds.md index 8f78a6937e..dc8985226c 100644 --- a/pl/tutorials/tour/lower-type-bounds.md +++ b/pl/tutorials/tour/lower-type-bounds.md @@ -11,7 +11,7 @@ tutorial-next: inner-classes tutorial-previous: upper-type-bounds --- -Podczas gdy [górne ograniczenia typów](upper-type-bounds.html) zawężają typ do podtypu innego typu, *dolne ograniczenia typów* określają dany typ jako typ bazowy innego typu. Sformułowanie `T >: A` wyraża, że parametr typowy `T` lub typ abstrakcyjny `T` odwołuje się do typu bazowego `A`. +Podczas gdy [górne ograniczenia typów](upper-type-bounds.html) zawężają typ do podtypu innego typu, *dolne ograniczenia typów* określają dany typ jako typ bazowy innego typu. Sformułowanie `T >: A` wyraża, że parametr typu `T` lub typ abstrakcyjny `T` odwołuje się do typu bazowego `A`. Oto przykład w którym jest to użyteczne: diff --git a/pl/tutorials/tour/nested-functions.md b/pl/tutorials/tour/nested-functions.md index 6a94506714..40d349c004 100644 --- a/pl/tutorials/tour/nested-functions.md +++ b/pl/tutorials/tour/nested-functions.md @@ -11,7 +11,7 @@ tutorial-next: currying tutorial-previous: higher-order-functions --- -Scala pozwala na zagnieżdżanie definicji funkcji. Poniższy obiekt określa funkcję `filter`, która dla danej listy filtruje elementy większe bądź równe niż podany próg `threshold`: +Scala pozwala na zagnieżdżanie definicji funkcji. Poniższy obiekt określa funkcję `filter`, która dla danej listy filtruje elementy większe bądź równe podanemu progowi `threshold`: ```tut object FilterTest extends App { diff --git a/pl/tutorials/tour/pattern-matching.md b/pl/tutorials/tour/pattern-matching.md index b4a066c38d..886d11362c 100644 --- a/pl/tutorials/tour/pattern-matching.md +++ b/pl/tutorials/tour/pattern-matching.md @@ -24,7 +24,7 @@ object MatchTest1 extends App { } ``` -Blok kodu z wyrażeniami `case` definiuje funkcję, która przekształca liczby całkowite do łańcuchów znaków. Słowo kluczowe `match` pozwala w wygodny sposób zastosować dopasowanie wzorca do obiektu. +Blok kodu z wyrażeniami `case` definiuje funkcję, która przekształca liczby całkowite na łańcuchy znaków. Słowo kluczowe `match` pozwala w wygodny sposób zastosować dopasowanie wzorca do obiektu. Wzorce można także dopasowywać do różnych typów wartości: @@ -41,5 +41,5 @@ object MatchTest2 extends App { Pierwszy przypadek jest dopasowany, gdy `x` jest liczbą całkowitą równą `1`. Drugi określa przypadek, gdy `x` jest równe łańcuchowi znaków `"two"`. Ostatecznie mamy wzorzec dopasowania typu. Jest on spełniony gdy `x` jest dowolną liczbą całkowitą oraz gwarantuje, że `y` jest (statycznie) typu liczby całkowitej. -Dopasowanie wzorca w Scali jest najbardziej użyteczne z wykorzystaniem typów algebraicznych modelowanych przez [klasy case](case-classes.html). -Scala także pozwala też na używanie wzorców niezależnie od klas case, używając metody `unapply` definiowanej przez [obiekty ekstraktorów](extractor-objects.html). +Dopasowanie wzorca w Scali jest najbardziej użyteczne z wykorzystaniem typów algebraicznych modelowanych przez [klasy przypadków](case-classes.html). +Scala także pozwala też na używanie wzorców niezależnie od klas przypadków, używając metody `unapply` definiowanej przez [obiekty ekstraktorów](extractor-objects.html). diff --git a/pl/tutorials/tour/regular-expression-patterns.md b/pl/tutorials/tour/regular-expression-patterns.md index b8fb8ed6b2..c3caf9a43c 100644 --- a/pl/tutorials/tour/regular-expression-patterns.md +++ b/pl/tutorials/tour/regular-expression-patterns.md @@ -14,7 +14,7 @@ tutorial-previous: xml-processing ## Wzorce sekwencji ignorujące prawą stronę ## -Wzorce ignorujące prawą stronę są użyteczne przy dekomponowaniu danych, które mogą być podtypem `Seq[A]` lub klasą case z iterowalnym parametrem, jak w poniższym przykładzie: +Wzorce ignorujące prawą stronę są użyteczne przy dekomponowaniu danych, które mogą być podtypem `Seq[A]` lub klasą przypadku z iterowalnym parametrem, jak w poniższym przykładzie: ``` Elem(prefix:String, label:String, attrs:MetaData, scp:NamespaceBinding, children:Node*) diff --git a/pl/tutorials/tour/singleton-objects.md b/pl/tutorials/tour/singleton-objects.md index b1696b689e..4f97924d7e 100644 --- a/pl/tutorials/tour/singleton-objects.md +++ b/pl/tutorials/tour/singleton-objects.md @@ -26,13 +26,13 @@ Metoda `sum` jest dostępna globalnie i można się do niej odwołać lub import Obiekty singleton są swego rodzaju skrótem do definiowania pojedynczej instancji klasy, która nie powinna być bezpośrednio tworzona i która sama w sobie stanowi referencję do tego obiektu, jakby była określona jako `val`. -Obiekt singleton może rozszerzać klasę lub cechę. Przykładowo [klasa case](case-class.html) bez [parametrów typu](generic-class.html), domyślnie generuje obiekt singleton o tej samej nazwie, który implementuje cechę [`Function*`](http://www.scala-lang.org/api/current/scala/Function1.html). +Obiekt singleton może rozszerzać klasę lub cechę. Przykładowo [klasa przypadku](case-class.html) bez [parametrów typu](generic-class.html), domyślnie generuje obiekt singleton o tej samej nazwie, który implementuje cechę [`Function*`](http://www.scala-lang.org/api/current/scala/Function1.html). -## Companion ## +## Obiekt towarzyszący ## -Duża część obiektów singleton nie istnieje samodzielnie, ale jest powiązana z klasą o tej samej nazwie. Obiekt singleton generowany dla klasy case jest tego przykładem. Kiedy tak się dzieje, obiekt singleton jest zwany *obiektem companion* (co oznacza, że jest _towarzyszem_ tej klasy). +Duża część obiektów singleton nie istnieje samodzielnie, ale jest powiązana z klasą o tej samej nazwie. Obiekt singleton generowany dla klasy przypadku jest tego przykładem. Kiedy tak się dzieje, obiekt singleton jest zwany *obiektem towarzyszącym*. -Klasa i jej obiekt companion mogą być zdefiniowane tylko w tym samym pliku, przykład: +Klasa i jej obiekt towaryszący mogą być zdefiniowane tylko w tym samym pliku, przykład: ```tut class IntPair(val x: Int, val y: Int) @@ -45,13 +45,13 @@ object IntPair { } ``` -Bardzo powszechne jest użycie wzorca typeclass w połączeniu z [wartościami implicit](implicit-parameters.html), takich jak `ipord` powyżej, zdefiniowanych w obiekcie companion. Dzieje się tak, ponieważ elementy obiektu companion są włączone w procesie wyszukiwania domyślnych wartości implicit. +Bardzo powszechne jest użycie wzorca typeclass w połączeniu z [wartościami domniemanymi](implicit-parameters.html), takich jak `ipord` powyżej, zdefiniowanych w obiekcie towarzyszącym. Dzieje się tak, ponieważ elementy obiektu towarzyszącego są uwzględniane w procesie wyszukiwania domyślnych wartości domniemanych. ## Uwagi dla programistów Javy ## `static` nie jest słowem kluczowym w Scali. Zamiast tego, wszystkie elementy, które powinny być statyczne (wliczając w to klasy) powinny zostać zamieszczone w obiekcie singleton. -Często spotykanym wzorcem jest definiowanie statycznych elementów, np. jako prywatne, pomocniczo dla ich instancji. W Scali przenosi się je do obiektu companion: +Często spotykanym wzorcem jest definiowanie statycznych elementów, np. jako prywatne, pomocniczo dla ich instancji. W Scali przenosi się je do obiektu towarzyszącego: ``` class X { @@ -65,6 +65,6 @@ object X { } ``` -Ten przykład ilustruje inną właściwość Scali: w kontekście zasięgu prywatnego, klasa i jej companion mają wzajemny dostęp do swoich pól. Aby sprawić, że dany element klasy jest *naprawdę* prywatny należy go zadeklarować jako `private[this]`. +Ten przykład ilustruje inną właściwość Scali: w kontekście zasięgu prywatnego, klasa i jej obiekt towarzyszący mają wzajemny dostęp do swoich pól. Aby sprawić, żeby dany element klasy jest *naprawdę* stał się prywatny należy go zadeklarować jako `private[this]`. -Dla wygodnej współpracy z Javą, metody oraz pola klasy w obiekcie singleton, mają także statyczne metody zdefiniowane w obiekcie companion, nazywane *static forwarder*. Dostęp do innych elementów można uzyskać poprzez statyczne pole `X$.MODULE$` dla obiektu `X`. +Dla wygodnej współpracy z Javą, metody oraz pola klasy w obiekcie singleton, mają także statyczne metody zdefiniowane w obiekcie towarzyszącym, nazywane *static forwarder*. Dostęp do innych elementów można uzyskać poprzez statyczne pole `X$.MODULE$` dla obiektu `X`. diff --git a/pl/tutorials/tour/tour-of-scala.md b/pl/tutorials/tour/tour-of-scala.md index 5fb50d8920..7026b44557 100644 --- a/pl/tutorials/tour/tour-of-scala.md +++ b/pl/tutorials/tour/tour-of-scala.md @@ -17,7 +17,7 @@ Scala jest nowoczesnym, wieloparadygmatowym językiem programowania zaprojektowa Scala jest czysto obiektowym językiem w tym sensie, że każda [wartość jest obiektem](unified-types.html). Typy oraz zachowania obiektów są opisane przez [klasy](classes.html) oraz [cechy](traits.html). Klasy są rozszerzane przez podtypowanie i elastyczny mechanizm [kompozycji domieszek](mixin-class-composition.html) jako zastępnik dla wielodziedziczenia. ## Scala jest funkcyjna ## -Scala jest też funkcyjnym językiem w tym sensie, że [każda funkcja jest wartością](unified-types.html). Scala dostarcza [lekką składnię](anonymous-function-syntax.html) do definiowana funkcji anonimowych, wspiera [funkcje wyższego rzędu](higher-order-functions.html), pozwala funkcjom by były [zagnieżdżone](nested-functions.html) oraz umożliwia [rozwijanie funkcji](currying.html). [Klasy case](case-classes.html) oraz wbudowane wsparcie dla [dopasowania wzorców](pattern-matching.html) wprowadzają do Scali mechanizm typów algebraicznych, stosowany w wielu funkcyjnych językach programowania. [Obiekty singleton](singleton-objects) są wygodną metodą grupowania funkcji, które nie należą do żadnej klasy. +Scala jest też funkcyjnym językiem w tym sensie, że [każda funkcja jest wartością](unified-types.html). Scala dostarcza [lekką składnię](anonymous-function-syntax.html) do definiowana funkcji anonimowych, wspiera [funkcje wyższego rzędu](higher-order-functions.html), pozwala funkcjom by były [zagnieżdżone](nested-functions.html) oraz umożliwia [rozwijanie funkcji](currying.html). [Klasy przypadków](case-classes.html) oraz wbudowane wsparcie dla [dopasowania wzorców](pattern-matching.html) wprowadzają do Scali mechanizm typów algebraicznych, stosowany w wielu funkcyjnych językach programowania. [Obiekty singleton](singleton-objects) są wygodną metodą grupowania funkcji, które nie należą do żadnej klasy. Ponadto, mechanizm dopasowania wzorca w naturalny sposób rozszerza się do obsługi [przetwarzania danych w formacie XML](xml-processing.html) z pomocą [wzorców sekwencji ignorujących prawą stronę](regular-expression-patterns.html), z wykorzystaniem rozszerzeń [obiektów ekstraktorów](extractor-objects.html). W tym kontekście, [instrukcje for](sequence-comprehensions.html) są użyteczne w formułowaniu zapytań. Ta funkcjonalność sprawia, że Scala jest idealnym językiem do tworzenia aplikacji takich jak usługi sieciowe. @@ -30,7 +30,7 @@ Scala posiada ekspresywny system typów, który zapewnia, że abstrakcje są uż * [klasy zagnieżdżone](inner-classes.html) i [typy abstrakcyjne](abstract-types.html) jako elementy obiektów * [typy złożone](compound-types.html) * [jawnie typowane samoreferencje](explicitly-typed-self-references.html) -* [parametry implicit](implicit-parameters.html) i [konwersje](implicit-conversions.html) +* [parametry domniemane](implicit-parameters.html) i [konwersje niejawne](implicit-conversions.html) * [metody polimorficzne](polymorphic-methods.html) [Mechanizm lokalnej inferencji typów](local-type-inference.html) sprawia, że nie jest konieczne podawanie nadmiarowych informacji o typach w programie. W połączeniu, te funkcje języka pozwalają na bezpiecznie typowane ponowne wykorzystanie programistycznych abstrakcji. diff --git a/pl/tutorials/tour/upper-type-bounds.md b/pl/tutorials/tour/upper-type-bounds.md index dc2f604aca..8053bcde2a 100644 --- a/pl/tutorials/tour/upper-type-bounds.md +++ b/pl/tutorials/tour/upper-type-bounds.md @@ -11,7 +11,7 @@ tutorial-next: lower-type-bounds tutorial-previous: variances --- -W Scali [parametry typów](generic-classes.html) oraz [typy abstrakcyjne](abstract-types.html) mogą być warunkowane przez ograniczenia typów. Tego rodzaju ograniczenia pomagają określić konkretne wartości zmiennych typu oraz odkryć więcej informacji na temat elementów tych typów. _Ograniczenie górne typu_ `T <: A` zakładają, że zmienna `T` odwołuje się jest podtypem typu `A`. +W Scali [parametry typów](generic-classes.html) oraz [typy abstrakcyjne](abstract-types.html) mogą być warunkowane przez ograniczenia typów. Tego rodzaju ograniczenia pomagają określić konkretne wartości zmiennych typu oraz odkryć więcej informacji na temat elementów tych typów. _Ograniczenie górne typu_ `T <: A` zakładają, że zmienna `T` jest podtypem typu `A`. Poniższy przykład demonstruje zastosowanie ograniczeń górnych typu dla parametru typu klasy `Cage`: diff --git a/pl/tutorials/tour/variances.md b/pl/tutorials/tour/variances.md index 6224a26200..a8148c4bc2 100644 --- a/pl/tutorials/tour/variances.md +++ b/pl/tutorials/tour/variances.md @@ -13,7 +13,7 @@ tutorial-previous: generic-classes Scala wspiera adnotacje wariancji parametrów typów [klas generycznych](generic-classes.html). W porównaniu do Javy, adnotacje wariancji mogą zostać dodane podczas definiowania abstrakcji klasy, gdy w Javie adnotacje wariancji są podane przez użytkowników tych klas. -Na stronie o [klasach generycznych](generic-classes.html) omówiliśmy przykład zmiennego stosu. Wyjaśniliśmy, że typ definiowany przez klasę `Stack[T]` jest poddany niezmiennemu podtypowaniu w stosunku do parametru typu. Może to ograniczyć możliwość ponownego wykorzystania abstrakcji tej klasy. Spróbujemy teraz opracować funkcyjną (tzn. immutable) implementację dla stosów, które nie posiadają tego ograniczenia. Warto zwrócić uwagę na to, że jest to zaawansowany przykład łączący w sobie zastosowanie [funkcji polimorficznych](polymorphic-methods.html), [dolnych ograniczeń typu](lower-type-bounds.html) oraz kowariantnych adnotacji parametru typu. Dodatkowo stosujemy też [klasy wewnętrzne](inner-classes.html), aby połączyć ze sobą elementy stosu bez jawnych powiązań. +Na stronie o [klasach generycznych](generic-classes.html) omówiliśmy przykład zmiennego stosu. Wyjaśniliśmy, że typ definiowany przez klasę `Stack[T]` jest poddany niezmiennemu podtypowaniu w stosunku do parametru typu. Może to ograniczyć możliwość ponownego wykorzystania abstrakcji tej klasy. Spróbujemy teraz opracować funkcyjną (tzn. niemutowalną) implementację dla stosów, które nie posiadają tego ograniczenia. Warto zwrócić uwagę na to, że jest to zaawansowany przykład łączący w sobie zastosowanie [funkcji polimorficznych](polymorphic-methods.html), [dolnych ograniczeń typu](lower-type-bounds.html) oraz kowariantnych adnotacji parametru typu. Dodatkowo stosujemy też [klasy wewnętrzne](inner-classes.html), aby połączyć ze sobą elementy stosu bez jawnych powiązań. ```tut class Stack[+A] {