Практические примеры использования символов в Scala? - PullRequest
62 голосов
/ 25 августа 2009

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

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

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

Ответы [ 8 ]

33 голосов
/ 25 августа 2009

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

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

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

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

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

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

18 голосов
/ 11 июня 2010

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

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

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

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

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

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

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

15 голосов
/ 26 августа 2009

Я думаю, 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.

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

15 голосов
/ 25 августа 2009

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

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

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

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

5 голосов
/ 25 августа 2009

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

3 голосов
/ 25 августа 2009

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

Это немного незначительно, хотя я не совсем убежден.

1 голос
/ 24 декабря 2015

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

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

Символы

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

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

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

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

1 голос
/ 03 ноября 2013

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

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 соответствующая сигнатура метода действительно использует тип символа Symbol.

...