Jakie są ukryte funkcje Scali, o których powinien wiedzieć każdy programista Scali?
Proszę o jedną ukrytą funkcję na odpowiedź.
scala
hidden-features
Krzysiek Goj
źródło
źródło
Odpowiedzi:
OK, musiałem dodać jeszcze jednego. Każdy
Regex
obiekt w Scali ma ekstraktor (patrz odpowiedź z oxbox_lakes powyżej), który daje dostęp do grup dopasowań. Możesz więc zrobić coś takiego:Druga linia wygląda myląco, jeśli nie jesteś przyzwyczajony do używania dopasowywania wzorców i ekstraktorów. Za każdym razem, gdy definiujesz
val
lubvar
, to, co pojawia się po słowie kluczowym, nie jest po prostu identyfikatorem, ale raczej wzorcem. Dlatego to działa:Wyrażenie po prawej stronie tworzy,
Tuple3[Int, Double, String]
które może pasować do wzorca(a, b, c)
.Przez większość czasu wzorce używają ekstraktorów, które są członkami obiektów pojedynczych. Na przykład, jeśli napiszesz wzór, taki jak
to niejawnie wywołujesz ekstraktor
Some.unapply
.Ale możesz także używać instancji klas we wzorcach i to właśnie się tutaj dzieje. Val regex jest instancją
Regex
, a kiedy używasz go we wzorcu, wywołujesz niejawnieregex.unapplySeq
(wunapply
przeciwieństwie do tego, żeunapplySeq
jest poza zakresem tej odpowiedzi), co wyodrębnia grupy dopasowań do aSeq[String]
, których elementy są przypisane w celu zmienne rok, miesiąc i dzień.źródło
Definicje typów strukturalnych - tj. Typ opisywany przez obsługiwane metody. Na przykład:
Zauważ, że typ parametru
closeable
nie jest zdefiniowany inaczej niż maclose
metodęźródło
Polimorfizm konstruktora typu (inaczej typy wyższego rodzaju)
Bez tej funkcji możesz na przykład wyrazić pomysł odwzorowania funkcji na liście w celu zwrócenia innej listy lub odwzorowania funkcji na drzewie w celu zwrócenia innego drzewa. Ale nie możesz ogólnie wyrazić tego pomysłu bez wyższych rodzajów.
W przypadku wyższych rodzajów można uchwycić ideę dowolnego typu sparametryzowaną innym typem. Mówi się, że konstruktor typu, który przyjmuje jeden parametr, jest rodzaju
(*->*)
. Na przykładList
. Mówi się, że konstruktor typu, który zwraca inny konstruktor typu, jest rodzaju(*->*->*)
. Na przykładFunction1
. Ale w Scali mamy wyższe rodzaje, więc możemy mieć konstruktory typów, które są sparametryzowane za pomocą innych konstruktorów typów. Więc są tego rodzaju((*->*)->*)
.Na przykład:
Teraz, jeśli masz
Functor[List]
, możesz mapować listy. Jeśli maszFunctor[Tree]
, możesz mapować drzewa. Ale co ważniejsze, jeśli maszFunctor[A]
dla dowolnego rodzaju A(*->*)
, możesz zmapować funkcjęA
.źródło
Ekstraktory, które pozwalają zastąpić niechlujny
if-elseif-else
kod stylu wzorami. Wiem, że nie są one dokładnie ukryte, ale używam Scali od kilku miesięcy, nie rozumiejąc ich mocy. Na (długi) przykład mogę wymienić:Dzięki temu, co moim zdaniem jest znacznie jaśniejsze
Muszę trochę popracować w tle ...
Ale praca jest tego warta, ponieważ oddziela kawałek logiki biznesowej w rozsądne miejsce. Mogę zaimplementować moje
Product.getCode
metody w następujący sposób.źródło
Manifesty, które są swego rodzaju sposobem uzyskiwania informacji o typie w czasie wykonywania, tak jakby Scala miała typy zreifikowane.
źródło
W scali 2.8 możesz mieć metody rekurencyjne typu tail, używając pakietu scala.util.control.TailCalls (w rzeczywistości jest to trampolinowanie).
Przykład:
źródło
Klasy Case automatycznie łączą cechę Product, zapewniając nietypowy, indeksowany dostęp do pól bez żadnej refleksji:
Ta funkcja zapewnia również uproszczony sposób zmiany wyniku
toString
metody:źródło
Nie jest to dokładnie ukryte, ale z pewnością niedostatecznie reklamowana funkcja: scalac -Xprint .
Jako ilustrację zastosowania rozważ następujące źródło:
Kompilując to za pomocą wyjścia scalac -Xprint: typer :
Uwaga
scala.this.Predef.augmentString("xx").r
, która jest aplikacjąimplicit def augmentString
obecną w Predef.scala.scalac -Xprint: <faza> wypisze drzewo składni po jakiejś fazie kompilatora. Aby zobaczyć dostępne fazy, użyj scalac -Xshow-phases .
To świetny sposób, aby dowiedzieć się, co dzieje się za kulisami.
Spróbuj z
case class X(a:Int,b:String)
wykorzystując fazę typer, aby naprawdę poczuć, jak jest ona użyteczna.
źródło
Możesz zdefiniować własne struktury sterowania. To tak naprawdę tylko funkcje i obiekty oraz trochę cukru syntaktycznego, ale wyglądają i zachowują się jak prawdziwe.
Na przykład poniższy kod definiuje
dont {...} unless (cond)
idont {...} until (cond)
:Teraz możesz wykonać następujące czynności:
źródło
zif[A : Zero](cond: => Boolean)(t: => A): A = if(cond) t else mzero
. Wymaga Scalaz.@switch
adnotacja w Scali 2.8:Przykład:
źródło
Nie wiem, czy to jest naprawdę ukryte, ale uważam to za całkiem miłe.
Konstruktory typów, które przyjmują 2 parametry typu, można zapisać w notacji wrostkowej
źródło
var foo2barConverter: Foo ConvertTo Bar
sprawi, że kolejność parametrów typu będzie oczywista.Scala 2.8 wprowadziła domyślne i nazwane argumenty, co umożliwiło dodanie nowej metody "kopiowania", którą Scala dodaje do klas przypadków. Jeśli to zdefiniujesz:
i chcesz utworzyć nowe Foo podobne do istniejącego Foo, tylko z inną wartością „n”, możesz po prostu powiedzieć:
źródło
w scali 2.8 możesz dodać @specialized do swoich klas / metod ogólnych. Spowoduje to utworzenie specjalnych wersji klasy dla typów pierwotnych (rozszerzenie AnyVal) i zaoszczędzenie kosztów niepotrzebnego pakowania / rozpakowywania:
class Foo[@specialized T]...
Możesz wybrać podzbiór AnyVals:
class Foo[@specialized(Int,Boolean) T]...
źródło
Rozszerzenie języka. Zawsze chciałem zrobić coś takiego w Javie (nie mogłem). Ale w Scali mogę mieć:
a potem napisz:
i dostać
źródło
Możesz wyznaczyć parametr wywołania według nazwy (EDYCJA: to jest inny niż parametr leniwy!) Do funkcji i nie będzie on oceniany, dopóki nie zostanie użyty przez funkcję (EDYCJA: w rzeczywistości zostanie ponownie oszacowany za każdym razem, gdy jest używany). Zobacz ten FAQ, aby uzyskać szczegółowe informacje
źródło
lazy val xx: Bar = x
w swojej metodzie i od tego momentu używasz tylkoxx
.Możesz użyć,
locally
aby wprowadzić blok lokalny bez powodowania problemów z wnioskami średnikami.Stosowanie:
locally
jest zdefiniowany w „Predef.scala” jako:Będąc w linii, nie nakłada żadnych dodatkowych kosztów.
źródło
Wczesna inicjalizacja:
Wynik:
źródło
Możesz komponować typy strukturalne za pomocą słowa kluczowego „with”
źródło
składnia symbolu zastępczego dla funkcji anonimowych
Ze specyfikacji języka Scala:
Z zmian języka Scala :
Używając tego, możesz zrobić coś takiego:
źródło
Niejawne definicje, zwłaszcza konwersje.
Na przykład załóżmy, że funkcja, która sformatuje ciąg wejściowy tak, aby pasował do rozmiaru, zastępując jego środek znakiem „...”:
Możesz tego użyć z dowolnym ciągiem i oczywiście użyć metody toString do konwersji wszystkiego. Ale możesz też napisać to tak:
Następnie możesz przejść zajęcia innego typu, wykonując następujące czynności:
Teraz możesz wywołać tę funkcję, przekazując double:
Ostatni argument jest niejawny i jest przekazywany automatycznie z powodu niejawnej deklaracji. Ponadto "s" jest istnieniem traktowane jak String wewnątrz sizeBoundedString, ponieważ następuje niejawna konwersja z niego na String.
Implikacje tego typu są lepiej zdefiniowane dla nietypowych typów, aby uniknąć nieoczekiwanych konwersji. Możesz również jawnie przekazać konwersję i nadal będzie ona niejawnie używana wewnątrz sizeBoundedString:
Możesz również mieć wiele niejawnych argumentów, ale wtedy musisz albo przekazać je wszystkie, albo nie przekazywać żadnego z nich. Istnieje również składnia skrótów dla niejawnych konwersji:
To jest używane dokładnie w ten sam sposób.
Implikacje mogą mieć dowolną wartość. Można ich użyć na przykład do ukrycia informacji bibliotecznych. Weźmy na przykład następujący przykład:
W tym przykładzie wywołanie „f” w obiekcie Y spowoduje wysłanie dziennika do demona domyślnego, a na instancji X do demona Daemon X. Ale wywołanie g na instancji X wyśle dziennik do jawnie podanego DefaultDaemon.
Chociaż ten prosty przykład można ponownie napisać z przeciążeniem i stanem prywatnym, implicity nie wymagają stanu prywatnego i można je umieścić w kontekście za pomocą importu.
źródło
Może niezbyt ukryte, ale myślę, że jest to przydatne:
Spowoduje to automatyczne wygenerowanie metody pobierającej i ustawiającej dla pola zgodnego z konwencją fasoli.
Dalszy opis w pracach deweloperskich
źródło
Niejawne argumenty w domknięciach.
Argument funkcji można oznaczyć jako niejawny, tak jak w przypadku metod. W zakresie treści funkcji niejawny parametr jest widoczny i kwalifikuje się do niejawnego rozwiązania:
źródło
Twórz nieskończone struktury danych za pomocą Scali
Stream
: http://www.codecommit.com/blog/scala/infinite-lists-for-the-finitely-patientźródło
Typy wyników zależą od niejawnego rozwiązania. Może to dać formę wielokrotnej wysyłki:
źródło
foo
zastosowań,a
które musiały być obecne w środowisku przed wykonaniem tych poleceń. Zakładam, że miałeś na myśliz.perform(x)
.Scala jest odpowiednikiem inicjatora podwójnego nawiasu klamrowego Java.
Scala umożliwia utworzenie anonimowej podklasy z treścią klasy (konstruktora) zawierającą instrukcje do zainicjowania instancji tej klasy.
Ten wzorzec jest bardzo przydatny podczas budowania interfejsów użytkownika opartych na komponentach (na przykład Swing, Vaadin), ponieważ umożliwia tworzenie komponentów UI i bardziej zwięzłe deklarowanie ich właściwości.
Więcej informacji można znaleźć pod adresem http://spot.colorado.edu/~reids/papers/how-scala-experience-improved-our-java-development-reid-2011.pdf .
Oto przykład tworzenia przycisku Vaadin:
źródło
Wyłączanie członków z
import
oświadczeńZałóżmy, że chcesz użyć metody
Logger
zawierającej aprintln
iprinterr
metodę, ale chcesz używać tylko tej dla komunikatów o błędach i zachować stare dobrePredef.println
dla standardowego wyjścia. Możesz to zrobić:ale jeśli
logger
zawiera również kolejne dwanaście metod, które chciałbyś zaimportować i użyć, ich lista staje się niewygodna. Zamiast tego możesz spróbować:ale to nadal „zanieczyszcza” listę importowanych członków. Wpisz niezwykle potężną kartę wieloznaczną:
a to wystarczy ™.
źródło
require
metoda (zdefiniowana wPredef
), która umożliwia zdefiniowanie dodatkowych ograniczeń funkcji, które byłyby sprawdzane w czasie wykonywania. Wyobraź sobie, że tworzysz kolejnego klienta Twittera i musisz ograniczyć długość tweeta do 140 symboli. Ponadto nie możesz publikować pustego tweeta.Teraz wywołanie posta z niewłaściwym argumentem długości spowoduje wyjątek:
Możesz napisać wiele wymagań lub nawet dodać opis do każdego:
Teraz wyjątki są szczegółowe:
Tutaj jest jeszcze jeden przykład .
Premia
Możesz wykonać akcję za każdym razem, gdy wymaganie nie powiedzie się:
źródło
require
nie jest słowem zastrzeżonym. To tylko metoda zdefiniowana wPredef
.Cechy z
abstract override
metodami to funkcja w Scali, która nie jest tak szeroko reklamowana, jak wiele innych. Celem metod zabstract override
modyfikatorem jest wykonanie pewnych operacji i delegowanie wywołania dosuper
. Następnie cechy te należy wymieszać z konkretnymi implementacjami ichabstract override
metod.Chociaż mój przykład jest naprawdę niewiele więcej niż kiepskim człowiekiem AOP, użyłem tych Stackable Traits bardzo do moich upodobań do zbudowania instancji interpretera Scala z predefiniowanymi importami, niestandardowymi powiązaniami i klasami. W Nakładane cechy pozwoliły stworzyć moją fabrykę wzdłuż linii
new InterpreterFactory with JsonLibs with LuceneLibs
, a następnie mieć użytecznych importu i zakres varibles dla skryptów użytkowników.źródło