Praktyczne przykłady użycia symboli w Scali?

Scala posiada symbole-Nazwy zaczynające się od pojedynczego cudzysłowu i będące rodzajem stałych łańcuchowych.

Znam symbole z Ruby (gdzie zaczynają się od dwukropka). W Ruby są one używane do niektórych zadań meta-programowania, takich jak generowanie getterów i setterów dla zmiennych członkowskich (na przykład attr_reader :name do generowania gettera dla name).

Nie widziałem jeszcze zbyt dużo użycia symboli w kodzie Scali. Jakie są praktyczne zastosowania symboli w Scali?

Author: Jesper, 2009-08-25

8 answers

Czy symbole naprawdę pasują do Scali?

We wspaniałej krainie Lispu, kod jest reprezentowany jako zagnieżdżone listy obiektów literalnych, które same się oznaczają (ciągi znaków, liczby itp.), oraz symbole, które są używane jako identyfikatory dla takich rzeczy jak klasy, funkcje i zmienne. Ponieważ Lisp ma bardzo prostą strukturę, Lisp pozwala programistom na manipulowanie nim (zarówno w czasie kompilacji, jak i podczas wykonywania). Oczywiście, gdy to zrobisz, programista nieuchronnie natknie się na symbole jako dane obiektów.

Więc symbole są (i muszą być) obiektami w Lispie, więc dlaczego nie używać ich jako kluczy tabel hashowych lub jako enums? Jest to naturalny sposób robienia rzeczy i utrzymuje prosty język, ponieważ nie musisz definiować specjalnego typu wyliczeń.

Podsumowując, symbole są naturalnie używane do manipulacji kodem, wyliczania i keying. Ale ludzie Javy nie używają tożsamości jako relacji równoważności między kluczami hashowymi domyślnie (co robi tradycyjny Lisp), więc mogą używać sznurków jako kluczy. Typy Enum są definiowane oddzielnie w Scali. I wreszcie, kod jako dane nie jest w ogóle obsługiwany przez język.

Więc nie, mam wrażenie, że symbole nie należą do języka Scali. To powiedziawszy, zamierzam mieć oko na odpowiedzi na to pytanie. Mogą nadal demonstrować prawdziwe użycie symboli w Scali, o czym nie mogę teraz myśleć.

(Addendum: w zależności od dialektu Lispu, Symbole Lispu mogą być również namespace-qualified, co jest oczywiście niezmiernie użyteczną funkcją podczas manipulowania kodem, oraz funkcją, której ciągi znaków nie mają.)

 33
Author: Matthias Benkard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-25 08:18:41

Szukając trochę po sieci wydaje się, że sens symboli (literałów symboli) w (takim języku) Scali w porównaniu z ciągami jest kwestią semantyki, a więc być może nawet świadomości kompilatora.

'String' jest typem danych, składającym się z sekwencji znaków. Możesz operować na strunach i manipulować nimi. Ciągi mogą być semantycznie dowolnymi danymi tekstowymi, od nazwy pliku po wiadomość do wydrukowania na ekranie, linię w pliku CSV lub cokolwiek innego.

Dla compiler - a więc IDE-strings są wartościami typu danych String, tak jak liczby (ciągi cyfr) są wartościami typu danych say: Integer . Na poziomie programu nie ma różnicy między " foo " a "bar".

Otoh to identyfikatory, czyli semantycznie identyfikujące element w programie. W tej materii są one jak nazwy klas, metod lub nazw atrybutów. Natomiast nazwa klasy identyfikuje klasę -tzn. zbiór właściwości deklarujących strukturę klasy i zachowanie-a nazwa metody identyfikuje metodę - tzn. parametry i polecenia -, nazwa symbolu identyfikuje symbol-tzn. sam, nic więcej- .

Kompilator może więc wyraźnie odróżnić symbole 'foo' i ' bar, tak jak rozróżnia klasy Foo i Bar. Jako część tabeli symboli kompilatora, możesz zastosować te same mechanizmy w IDE, np. do wyszukiwania użycia ' foo (tj. odniesień do tego symbolu), jak szukanie użycia klasy Foo.

Dla porównania, wyszukiwanie ciągu znaków " foo " wymagałoby różnych podejść, takich jak skanowanie pełnotekstowe. Podąża za tą samą semantyką, co szukanie wszystkich wystąpień 4711 w kodzie programu.

Tak to Rozumiem, ktoś może mnie poprawić, jeśli się mylę.

 17
Author: Det,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-11 08:50:59

Zgodnie z Księgą Scala, symbole są internowane: "Jeśli dwa razy napiszesz ten sam symbol, oba wyrażenia będą odnosiły się do dokładnie tego samego obiektu Symbol."

Natomiast, StringS są internowane tylko wtedy, gdy pojawiają się w dosłownej formie(przynajmniej w Javie są, nie do końca pewne co do Scali). Więc myślę, że jeśli robisz wiele serializacji String s, które są następnie umieszczane w kolekcjach, możesz użyć symboli zamiast tego i zaoszczędzić sobie trochę pamięci.

Ale Zgadzam się ze skaffmanem, Nie jestem do końca przekonany do ich użycia.

(W Rubim, Symbol s są, poza podanym przez Ciebie przykładem meta-programowania, często używane jako klucze w Hash es. W Rubim jest to przydatne, ponieważ tam String S nigdy nie są internowane: każda String przydziela nową pamięć. W Scali może się to przydać, jak wspomniałem, jeśli połączysz go z dużą ilością (de)serializacji, aby Java Stringrównież nie została internowana.)

 15
Author: jqno,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-24 20:29:24

Myślę, że Scala dodała je, ponieważ języki funkcyjne ich używają.

Zapomnieli jednak dodać możliwość odwoływania się do identyfikatora za pomocą symbolu, który jest swego rodzaju centralnym punktem ich istnienia. W Scali 2.8 jest funkcja eksperymentalna, która daje trochę tego. Zacytuję w całości odpowiednią część dokumentacji API:
@experimental

object Invocation 
extends AnyRef

Wygodniejsza składnia refleksyjnego wywołania. Przykład użycia:

    class Obj { private def foo(x: Int, y: String): Long = x + y.length }

Można to nazwać refleksyjnie jeden z dwóch sposobów:

    import scala.reflect.Invocation._
    (new Obj) o 'foo(5, "abc")                 // The 'o' method returns Any
    val x: Long = (new Obj) oo 'foo(5, "abc")  // The 'oo' method casts to expected type.

Jeśli wywołasz metodę oo i nie udzielisz wystarczającej pomocy typowi inferencer, najprawdopodobniej wywnioskuje ona Nothing, co spowoduje ClassCastException.

Autor Paul Phillips

 15
Author: Daniel C. Sobral,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-29 18:41:35

Uważam, że porównywanie symboli jest szybsze. Jeśli używałeś Erlanga, symbole są używane na tonę podczas przekazywania wiadomości i chcesz czegoś taniego i szybkiego, co działa dobrze poza granicami maszyny. Nie jestem pewien, w jakim stanie są aktorzy w Scali, IIRC, byli raczej podejrzani, ale w przyszłości, gdy będą na swoim miejscu, symbole mogą być bardzo przydatne w podobny sposób, jak w Erlang. Również klasy przypadków, niektóre korzyści nie są tak widoczne, z drugiej strony, symbole są nadal tańsze.

 5
Author: Saem,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-24 23:48:00

Przypuszczam, że użyłbyś ich, gdy chcesz odwołać się do nazwy rzeczy, która nie jest istniejącym identyfikatorem w kodzie. Książka Scala podaje przykład odwoływania się do nazwy kolumny bazy danych - nie jest to dowolny ciąg znaków, jest to właściwie nazwa rzeczy.

To trochę mało, ale nie jestem do końca przekonany.

 3
Author: skaffman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-24 20:11:33

Mogę wymienić jeden przypadek, gdy symbole są naprawdę używane w Scali. Play 2.2 używa anorm do dostępu do bazy danych. Oto przykład kodu dla prostej metody add entity:

def add(e:Entity): Option[Long] = {
    DB.withConnection {implicit conn =>
        SQL("insert into ENTITY(name, description) values({name}, {description})").on('name -> e.name, 'description -> e.description).executeInsert()
    }
}

Więc można zobaczyć użycie symboli w .on (bla bla bla) Jest również absolutnie poprawne używanie liter ciągów zamiast symboli i niektórzy tak robią, ale w kodzie źródłowym anorma odpowiednia sygnatura metody naprawdę używa symbolu paremeter type.

 1
Author: Alexander Arendar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-03 11:11:15

Jak już wspomniano, symbole przenoszą się z innych (bardziej) języków funkcyjnych. Inni nie wspominali o tym, że nie tylko pełnią one rolę symboli, ale są również najbliższym odpowiednikiem słów kluczowych (minus może przewaga wydajności). Moim zdaniem są one bardziej przydatne jako słowa kluczowe, czyli jednoznaczne identyfikatory.

Poniżej zamieszczę opis sądu z Clojure docs słów kluczowych i symboli.

Symbole

Symbole są identyfikatorami, które są zwykle używane do odwoływania się do czegoś innego. Mogą być używane w formularzach programu do odwoływania się do parametrów funkcji, powiązań let, nazw klas i globalnych VAR-ów. Mają nazwy i opcjonalne przestrzenie nazw, z których oba są ciągami znaków. Symbole mogą mieć metadane(zobacz z-meta).

Słowa kluczowe

Słowa kluczowe są identyfikatorami symbolicznymi, które same oceniają. Zapewniają one bardzo szybkie testy równości. Podobnie jak symbole, mają nazwy i opcjonalne przestrzenie nazw, z których oba to sznurki. Początkowe': 'nie jest częścią przestrzeni nazw ani nazwy.

Symbole Scali nie są tak potężne jak symbole w niektórych językach. Dlatego też nie są tak przydatne. Nie rozumiem jednak, dlaczego nie mogą oferować takich samych zalet meta-programowania i wydajności jak słowa kluczowe. Mogą one przynajmniej ułatwić odczyt Twojego kodu.

 1
Author: Dominykas Mostauskis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-25 13:56:15