Практические примеры использования символов в Scala?
В Scala есть символы - имена, начинающиеся с одинарных кавычек и являющиеся разновидностью строковых констант.
Я знаю символы из Ruby (где они начинаются с двоеточия). В Ruby они используются для некоторых задач метапрограммирования, таких как генерация геттеров и сеттеров для переменных-членов (например, attr_reader :name
создать геттер для name
).
Я еще не видел много символов в коде Scala. Как практично использовать символы в Scala?
8 ответов
Действительно ли символы вписываются в Scala?
В чудесной стране Лисп код представлен в виде вложенных списков литеральных объектов, обозначающих себя (строки, числа и т. Д.), И символов, которые используются в качестве идентификаторов для таких вещей, как классы, функции и переменные. Поскольку код на Лиспе имеет очень простую структуру, Лисп позволяет программисту манипулировать им (как во время компиляции, так и во время выполнения). Очевидно, что при этом программист неизбежно встретит символы в качестве объектов данных.
Так что символы в любом случае являются (и должны быть) объектами в Лиспе, так почему бы не использовать их как ключи хеш-таблицы или как перечисления? Это естественный способ работы, и он делает язык простым, так как вам не нужно определять специальный тип перечисления.
Подводя итог, символы естественным образом используются для манипулирования кодом, перечисления и ввода ключей. Но Java-люди не используют идентичность в качестве отношения эквивалентности между ключами хеш-функции по умолчанию (что делает ваш традиционный Lisp), поэтому они могут просто использовать строки в качестве своих ключей. Типы перечислений определяются отдельно в Scala. И, наконец, код как данные вообще не поддерживается языком.
Так что нет, у меня сложилось впечатление, что символы не принадлежат языку Скала. Тем не менее, я буду следить за ответами на этот вопрос. Они могут все еще демонстрировать подлинное использование символов в Scala, о котором я не могу думать прямо сейчас.
(Приложение: В зависимости от диалекта Лисп, символы Лисп также могут быть квалифицированы в пространстве имен, что, конечно, очень полезная функция при манипулировании кодом и функция, которой нет в строках.)
При поиске в Интернете кажется, что смысл символов (литералов символов) в Scala (подобный языку) по сравнению со строками - это вопрос семантики и, следовательно, даже понимания компилятора.
"String" - это тип данных, состоящий из последовательности символов. Вы можете оперировать строками и манипулировать ими. Семантически могут быть любые текстовые данные, от имени файла до сообщения, которое будет напечатано на экране, строки в файле CSV или чего-либо еще.
Для компилятора, и, следовательно, строки IDE являются значениями типа данных String, как числа (последовательности цифр) являются значениями типа данных, скажем: Integer . На уровне программы нет никакой разницы между "foo" и "bar".
Символы OTOH являются идентификаторами, то есть семантически идентифицирующими элемент в программе. В этом вопросе они похожи на имена классов, имена методов или имена атрибутов. Но в то время как имя класса идентифицирует класс - то есть набор свойств, объявляющих структуру и поведение класса - и имя метода идентифицирует метод - то есть параметры и операторы, - имя символа идентифицирует символ - сам по себе, ничего более -,
Таким образом, компилятор может явно различать символы "foo" и "bar", как он различает классы "Foo" и "Bar". Как часть таблицы символов компилятора, вы можете применять те же механизмы в IDE, например, для поиска использования 'foo (то есть ссылок на этот символ), как вы ищете для использования класса Foo.
Для сравнения, поиск строки "foo" потребовал бы разных подходов, например, полнотекстового сканирования. Он следует той же семантике, что и поиск всех вхождений 4711 в программном коде.
Вот как я понимаю, кто-то может поправить меня, если я ошибаюсь.
Я думаю, что 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
метод и не оказывать помощь типу вывода, это скорее всего будет вывод Nothing
, что приведет к ClassCastException
,
Автор Пол Филлипс
Согласно книге Scala, символы интернированы: " Если вы напишите один и тот же символ дважды, оба выражения будут относиться к одному и тому же Symbol
объект. "
По сравнению, String
Они интернируются, только если они появляются в буквальном виде (по крайней мере, в Java они не совсем уверены в Scala). Так что я думаю, если вы делаете много сериализации String
Если они помещены в коллекции, вы можете использовать вместо них символы и сэкономить себе память.
Но я согласен со скаффманом, я не совсем убежден в их использовании.
(В рубине Symbol
s, помимо приведенного вами примера метапрограммирования, часто используются как ключи в Hash
эс. В Ruby это полезно, потому что там, String
S никогда не интернированы: каждый String
выделяет новую память. В Scala это может быть полезно, как я уже говорил, если вы объединяете его с большим количеством (де) сериализации, так что Java String
и не интернируют.)
Я считаю, что сравнение между символами происходит быстрее. Если вы использовали Erlang, символы используют тонну при передаче сообщений, и вы хотите что-то дешевое и быстрое, которое хорошо работает через границы машин. Я не уверен, в каком состоянии находятся удаленные актеры в Scala, IIRC, они были довольно хитрыми, но в будущем, когда они появятся, символы могут быть очень полезны во многом так же, как в Эрланге. Кроме того, тематические классы, некоторые преимущества не так очевидны, опять же, символы все еще дешевле.
Я полагаю, вы использовали бы их, когда хотите сослаться на название вещи, которая не существует в коде идентификатора. В книге Scala приведен пример обращения к имени столбца базы данных - это не произвольная строка, а фактически название вещи.
Это немного ненадежно, хотя я не совсем убежден.
Я могу назвать один случай, когда символы действительно используются в 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 (бла-бла-бла). Также абсолютно допустимо использовать литералы String вместо символов, и некоторые парни делают это, но в исходном коде anorm соответствующий сигнатура метода действительно использует символьный пареметр тип.
Как уже отмечалось, перенос символов из других (более) функциональных языков. Что-то, что другие не упомянули, это то, что они не только выполняют роль символов, но они также являются ближайшим эквивалентом ключевых слов (возможно, минус преимущество в производительности). На мой взгляд, они более полезны в качестве ключевых слов, означающих явные идентификаторы.
Ниже я приведу описание суда из документов Clojure по ключевым словам и символам.
Символы
Символы - это идентификаторы, которые обычно используются для обозначения чего-то другого. Они могут использоваться в формах программы для ссылки на параметры функций, привязки, имена классов и глобальные переменные. У них есть имена и необязательные пространства имен, которые являются строками. Символы могут иметь метаданные (см. С-мета).
Ключевые слова
Ключевые слова - это символические идентификаторы, которые оценивают сами себя. Они обеспечивают очень быстрые тесты на равенство. Как и символы, у них есть имена и необязательные пространства имен, которые являются строками. Ведущий ':' не является частью пространства имен или имени.
Символы Scala не так мощны, как символы в некоторых языках. Поэтому они не так полезны. Однако я не понимаю, почему они не могут предложить те же преимущества метапрограммирования и производительности, что и ключевые слова. По крайней мере, они могут сделать ваш код проще для чтения.