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

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

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

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

Ответ 1

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

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

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

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

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

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

Ответ 2

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

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

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

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

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

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

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

Ответ 3

В соответствии с книгой Scala символы интернированы: "Если вы дважды пишете один и тот же символ, оба выражения будут ссылаться на тот же самый объект Symbol".

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

Но я согласен с скаффманом, я не совсем уверен в их использовании.

(В Ruby, Symbol, помимо примера метапрограммирования, который вы даете, часто используется как клавиши в Hash es. В Ruby это полезно, потому что там String никогда не интернированы: каждый String выделяет новую память. В Scala может быть полезно, как я уже упоминал, объединить его с серией сериализации (de), чтобы Java String также не попадал в интернирование.)

Ответ 4

Я предполагаю, что 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.

Автор Пол Филлипс

Ответ 5

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

Ответ 6

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

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

Ответ 7

Я могу назвать один случай, когда символы действительно используются в Scala. Play 2.2 использует анорму для доступа к базе данных. Здесь приведен пример кода для простого метода сущности добавления:

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()
    }
}

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

Ответ 8

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

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

Символы

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

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

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

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