Практические примеры использования символов в Scala?

Scala имеет символы-имена, которые начинаются с одной кавычки ' и которые являются своего рода строковыми константами.

Я знаю символы из Ruby (где они начинаются с двоеточия). В Ruby они используются для некоторых задач метапрограммирования, таких как генерация геттеров и сеттеров для переменных-членов (например,attr_reader :name создать геттер для name).

Я еще не видел много использования символов в коде Scala. Каковы практические применения символов в Scala?

8 ответов


действительно ли символы вписываются в Scala?

в чудесной стране Lisp код представлен как вложенные списки литеральных объектов, которые обозначают себя (строки, числа и т. д.), и символы, которые используются в качестве идентификаторов для таких вещей, как классы, функции и переменные. Поскольку код Lisp имеет очень простую структуру, Lisp позволяет программисту управлять им (как во время компиляции, так и во время выполнения). Очевидно, что при этом программист неизбежно столкнется с такими символами, как объекты-данные.

таким образом, символы являются (и должны быть) объектами в Lisp в любом случае, так почему бы не использовать их как ключи хэш-таблицы или как перечисления? Это естественный способ делать вещи, и он сохраняет язык простым, так как вам не нужно определять специальный тип перечисления.

обобщить, символы обычно используются для манипуляции с кодом, подсчет и манипуляция. Но люди Java не используют identity в качестве отношения эквивалентности между хэш-ключами по умолчанию (который ваш традиционный Лисп делает), поэтому они могут просто использовать строки в качестве ключей. Типы перечислений определяются отдельно в Scala. И, наконец, код как данные вообще не поддерживается языком.

Так что нет, мое впечатление, что символы не принадлежат к языку Scala. Тем не менее, я собираюсь следить за ответами на этот вопрос. Они все еще могут продемонстрировать подлинное использование символов в Scala, о которых я сейчас не могу думать.

(дополнение: в зависимости от диалект Lisp, символы Lisp также могут быть определены пространством имен, что, конечно, является чрезвычайно полезной функцией при манипулировании кодом и функцией, которой нет у строк.)


Поиск немного по сети кажется, что смысл символов (символьных литералов) в (таком языке, как) Scala по сравнению со строками является вопросом семантики, и, возможно, даже осознания компилятора.

'String' - это тип данных, состоящий из последовательности символов. Вы можете оперировать струнами и манипулировать ими. Строки могут семантически быть любыми текстовыми данными, от имени файла до сообщения для печати на экране, строки в CSV-файле или что угодно.

для компилятора - и, таким образом, IDE-строки являются значениями строки типа данных, как числа (последовательности цифр) являются значениями типа данных, скажем: Integer . На программном уровне нет разницы между" foo "и"bar".

OTOH символы являются идентификаторами, т. е. семантически идентифицирующими элемент в программе. В этом вопросе они похожи на имена классов, имена методов или атрибутов. Но в то время как имя класса идентифицирует класс -т. е. набор свойств объявление структуры и поведения класса-и имя метода идентифицирует метод-т. е. параметры и операторы- , имя символа идентифицирует символ-т. е. его самого, ничего больше- .

таким образом, компилятор может явно различать символы " foo " и " bar, как он различает классы Foo и Bar. Как часть таблицы символов компилятора, вы можете применить те же механизмы в IDE, например, для поиска использования ' foo (т. е. ссылок на это символ), как вы ищете для использования класса Foo.

для сравнения, поиск строки " foo " потребует различных подходов, таких как полнотекстовое сканирование. Он следует той же семантике, что и поиск всех вхождений 4711 в программном коде.

вот как я понимаю, кто-то может поправить меня, если я ошибаюсь.


согласно Книге Scala, символы интернированы:"если вы пишете один и тот же символ дважды, оба выражения будут относиться к одному и тому же


Я думаю, Scala добавил их, потому что функциональные языки используют их.

они забыли, однако, добавить способность ссылаться на идентификатор через символ, который является своего рода центральной точкой их существования. В Scala 2.8 есть экспериментальная функция, которая дает некоторые из них. Я приведу соответствующую часть документации API в полном объеме:


@experimental

object Invocation 
extends AnyRef

более удобный синтаксис для вызова светоотражающие. Пример использования:

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

вы можете назвать это рефлексивно одним из двух способов:

    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.

если вы называете oo метод и не дают типу inferencer достаточно помощи, он, скорее всего, выведет Nothing, что приведет к ClassCastException.

автор Пол Филлипс!--7-->


Я считаю, что сравнение между символами быстрее. Если вы использовали Erlang, символы используются тонну при передаче сообщений, и вы хотите что-то дешевое и быстрое, что хорошо работает через границы машины. Я не уверен, в каком состоянии находятся удаленные актеры в Scala, IIRC, они были довольно изворотливы, но в будущем, когда они на месте, символы могут быть очень полезны во многом так же, как и в Эрланге. Кроме того, классы case, некоторые из преимуществ не так очевидны, а затем снова, символы по-прежнему дешевле.


Я полагаю, вы будете использовать их, когда захотите сослаться на имя вещи, которая не является существующим идентификатором в коде. В книге Scala приведен пример ссылки на имя столбца базы данных-это не произвольная строка, это на самом деле имя вещи.

Это немного шатко, хотя я не совсем убежден.


Я могу назвать один случай, когда символы используются в Scala. Играть 2.2 использует anorm для доступа к базе данных. Вот пример кода для простого метода 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()
    }
}

таким образом, вы можете увидеть использование символов в .(бла-бла-бла!)) Также абсолютно допустимо использовать строковые литералы вместо символов, и некоторые ребята делают это, но в исходном коде anorm соответствующая сигнатура метода действительно использует символ типа paremeter.


Как уже отмечалось, символы переносятся с других (более) функциональных языков. Что-то другие не упоминали, что они не только заполняют роль символов, но они также являются ближайшим эквивалентом ключевых слов (минус преимущество производительности, возможно). На мой взгляд, они более полезны в качестве ключевых слов, что означает явные идентификаторы.

ниже я включу описание суда из Clojure docs ключевых слов и символов.

символы

символы являются идентификаторами, которые обычно используются для обозначения чего-то другого. Они могут использоваться в формах программ для ссылки на параметры функций, привязки let, имена классов и глобальные vars. Они имеют имена и необязательные пространства имен, оба из которых являются строками. Символы могут иметь метаданные (см. с-мета).

ключевые слова

ключевые слова являются символьными идентификаторами, которые оценивают сами по себе. Они обеспечивают очень быстрые тесты равенства. Как Символы, они имеют имена и необязательные пространства имен, оба из которых являются строками. Ведущее": "не является частью пространства имен или имени.

символы Scala не так сильны, как символы в некоторых языках. Поэтому они тоже не столь полезны. Однако я не понимаю, почему они не могут предложить те же преимущества метапрограммирования и производительности, что и ключевые слова. По крайней мере, они могут сделать ваш код более легким для чтения.