diff --git a/_pl/tour/case-classes.md b/_pl/tour/case-classes.md index 48c6683418..bc67870201 100644 --- a/_pl/tour/case-classes.md +++ b/_pl/tour/case-classes.md @@ -6,128 +6,70 @@ discourse: false partof: scala-tour -num: 10 +num: 11 language: pl next-page: pattern-matching previous-page: multiple-parameter-lists --- -Scala wspiera mechanizm _klas przypadków_. Klasy przypadków są zwykłymi klasami z dodatkowymi założeniami: +Scala wspiera mechanizm _klas przypadków_ (ang. case class). +Są one zwykłymi klasami z dodatkowymi założeniami, przez które przejdziemy. +Klasy przypadków idealnie nadają się do modelowania niezmiennych (niemutowalnych) danych. +W dalszych rozdziałach przyjrzymy się jak przydają się w [dopasowywaniu wzorców (ang. pattern matching)](pattern-matching.html). -* 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 +## Definiowanie klas przypadków -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`: +Minimalna definicja klasy przypadku wymaga słów kluczowych `case class`, identyfikatora oraz listy parametrów (może być pusta): ```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) +case class Book(isbn: String) -```tut -val emailFromJohn = Email("john.doe@mail.com", "Greetings From John!", "Hello World!") +val frankenstein = Book("978-0486282114") ``` -Parametry konstruktora klasy przypadków są traktowane jako publiczne wartości i można się do nich odwoływać bezpośrednio: +Zauważ, że słowo kluczowe `new` nie było konieczne do stworzenia instancji klasy przypadku `Book`. +Jest tak, ponieważ klasy przypadków posiadają domyślnie zdefiniowaną metodę `apply`, która zajmuje się tworzeniem obiektu klasy. -```tut -val title = emailFromJohn.title -println(title) // wypisuje "Greetings From John!" -``` +W przypadku, kiedy tworzymy klasę przypadku zawierającą parametry, są one publiczne i stałe (`val`). -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 przypadku są domyślnie niezmienne ``` +case class Message(sender: String, recipient: String, body: String) +val message1 = Message("guillaume@quebec.ca", "jorge@catalonia.es", "Ça va ?") -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!)" +println(message1.sender) // wypisze guillaume@quebec.ca +message1.sender = "travis@washington.us" // ten wiersz nie skompiluje się ``` -Dla każdej klasy przypadku kompilator Scali wygeneruje metodę `equals` implementującą strukturalne porównanie obiektów oraz metodę `toString`. Przykład: +Nie można ponownie przydzielić wartości do `message1.sender`, ponieważ jest to `val` (stała). +Alternatywnie, w klasach przypadków można też używać `var`, jednak stanowczo tego odradzamy. -```tut -val firstSms = SMS("12345", "Hello!") -val secondSms = SMS("12345", "Hello!") - -if (firstSms == secondSms) { - println("They are equal!") -} +## Porównywanie -println("SMS is: " + firstSms) -``` +Klasy przypadków są porównywane według ich struktury, a nie przez referencje: -Wypisze: +```tut +case class Message(sender: String, recipient: String, body: String) -``` -They are equal! -SMS is: SMS(12345, Hello!) +val message2 = Message("jorge@catalonia.es", "guillaume@quebec.ca", "Com va?") +val message3 = Message("jorge@catalonia.es", "guillaume@quebec.ca", "Com va?") +val messagesAreTheSame = message2 == message3 // true ``` -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: +Mimo, że `message1` oraz `message2` odnoszą się do innych obiektów, to ich wartości są identyczne. -```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)) // Wypisuje "You got an SMS from 12345! Message: Are you there?" -println(showNotification(someVoiceRecording)) // Wypisuje "you received a Voice Recording from Tom! Click the link to hear it: voicerecording.org/id/123" -``` +## Kopiowanie -Poniżej bardziej skomplikowany przykład używający `if` w celu określenia dodatkowych warunków dopasowania: +Możliwe jest stworzenie płytkiej kopii (ang. shallow copy) instancji klasy przypadku używając metody `copy`. +Opcjonalnie można zmienić jeszcze wybrane parametry konstruktora. ```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)) // Wypisuje "You got an SMS from 12345! Message: Are you there?" -println(showNotificationSpecial(someVoiceRecording, SPECIAL_EMAIL, SPECIAL_NUMBER)) // Wypisuje "you received a Voice Recording from Tom! Click the link to hear it: voicerecording.org/id/123" -println(showNotificationSpecial(specialEmail, SPECIAL_EMAIL, SPECIAL_NUMBER)) // Wypisuje "You got an email from special someone!" -println(showNotificationSpecial(specialSms, SPECIAL_EMAIL, SPECIAL_NUMBER)) // Wypisuje "You got an SMS from special someone!" +case class Message(sender: String, recipient: String, body: String) +val message4 = Message("julien@bretagne.fr", "travis@washington.us", "Me zo o komz gant ma amezeg") +val message5 = message4.copy(sender = message4.recipient, recipient = "claire@bourgogne.fr") +message5.sender // travis@washington.us +message5.recipient // claire@bourgogne.fr +message5.body // "Me zo o komz gant ma amezeg" ``` -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 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 - +Odbiorca wiadomości 4 `message4.recipient` jest użyty jako nadawca wiadomości 5 `message5.sender`, ciało wiadomości 5 zostało skopiowane bez zmian z wiadomości 4. diff --git a/_tour/case-classes.md b/_tour/case-classes.md index 607e449d0e..ee02b7406d 100644 --- a/_tour/case-classes.md +++ b/_tour/case-classes.md @@ -37,7 +37,7 @@ You can't reassign `message1.sender` because it is a `val` (i.e. immutable). It ## Comparison Case classes are compared by structure and not by reference: -``` +```tut case class Message(sender: String, recipient: String, body: String) val message2 = Message("jorge@catalonia.es", "guillaume@quebec.ca", "Com va?") @@ -48,7 +48,7 @@ Even though `message2` and `message3` refer to different objects, the value of e ## Copying You can create a (shallow) copy of an instance of a case class simply by using the `copy` method. You can optionally change the constructor arguments. -``` +```tut case class Message(sender: String, recipient: String, body: String) val message4 = Message("julien@bretagne.fr", "travis@washington.us", "Me zo o komz gant ma amezeg") val message5 = message4.copy(sender = message4.recipient, recipient = "claire@bourgogne.fr")