Зачем нам нужны перечисления в динамически типизированных языках?

32

Я читал некоторый код здесь и увидел, что enum используется для хранения имен тегов html. Почему мы когда-либо должны это делать? Какую выгоду я получу от этой стратегии?

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

CodeYogi
источник
38
Этот вопрос в основном «зачем нам типы» .
user11153
1
Вы искали репо, чтобы увидеть, как он называется? Это, вероятно, даст вам лучшее понимание ответов, которые вы получили.
RubberDuck
если у вас есть: enum People { YOU, NPC, FOO, BAR }и функция, которая хочет (Люди) int, вы можете подключить что угодно, вместо использования числа.
Эван Карслэйк,
3
Вы спрашиваете о цели этого конкретного "enum" или о цели enums в целом на каком-либо языке? Я бы предположил первое, но все текущие ответы, кажется, думают второе ...
меритон - бастует

Ответы:

56

Преимущество заключается в том, что компилятор может сообщить вам, если вы случайно набрали «ADRESS» или «FEILDSET», и позволить вам исправить это немедленно, а не вести себя бессмысленным образом во время выполнения.

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

как зовут
источник
4
@amon: вы могли бы, но enums дает вам удобный механизм, чтобы избежать коллизий.
whatsisname
75
В месте, где я раньше работал, потратил месяц, гоняясь за ошибкой, вызванной чьей-то яркой идеей использовать строковые константы вместо перечислений, плохие редакторские шрифты и случайно названное поле"PROF1LE_"
Gort the Robot
8
@amon Go делает именно это. Однако в перечислениях есть одна приятная вещь: компилятор может проверить, что в вашем операторе switch есть регистр для каждого возможного значения перечисления.
weberc2
15
Этот код был написан в 80-х годах. Вы можете не осознавать этого, но это было в эпоху, когда некоторые разработчики учились разрабатывать на физических пишущих машинках, у которых, возможно, не было одного ключа . Хотя на самом деле я понимаю, что речь шла о «Profi1e» ... прошло двадцать пять лет, поэтому моя память явно не идеальна.
Gort the Robot
4
@DarrelHoffman: Я удивлен, что ты удивлен. В Perl я часто печатаю, $1когда имею в виду $i. (Конечно, я никогда не печатаю f1leвместо file- $1ошибка вызвана тем, что $1это очень часто встречается в Perl - но, тем не менее, ошибки всех видов встречаются часто. Может быть, у разработчика был пароль с prof1leним, тем самым вводя их в опечатку profileв не-парольном контексте.)
ruakh
22

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

Более полезным примером будет что-то вроде HTTP-кода ответа. Вместо того, чтобы иметь метод, который принимает число и предоставляет имя и / или описание ошибки, вы можете иметь набор перечислений со значимыми именами, код, описание и т. Д. В одном чистом пакете, который является авторитетным в том, что значения разрешено и должно быть обработано.

JimmyJames
источник
1
«Самодокументирование» является наиболее важной частью. Я бы предпочел проверить, если, status === GEOLOCATION_ACQUIREDчем status === 3, чтобы человек, который поддерживает это программное обеспечение, понимал, что происходит. Как вы сказали, это также предотвращает недопустимые значения.
Николас Булиан
11

Перечисления не имеют ничего общего с ООП, а в JavaScript нет перечислений. Вместо этого перечисления используются всякий раз, когда есть выбор между фиксированным набором значений. Например, логическое значение - это выбор между истиной и ложью, который может быть реализован как enum Bool { False, True }. В библиотеке GUI, мы могли бы иметь перечисление для выравнивания: enum HAlignment { LEFT = -1, CENTER = 0, RIGHT = 1 }.

Как правило, не имеет значения, как реализовано перечисление, важная часть заключается в том, что каждое возможное значение отличается. Многие языки используют целые числа для перечислений, хотя некоторые, такие как Java, поддерживают произвольные объекты.

До сих пор мы могли бы использовать константы, например const int LEFT = -1, CENTER = 0, RIGHT = 1. Однако компилятор знает, что значения перечисления принадлежат друг другу. Поэтому, когда я переключаю значения enum switch(value) {case LEFT: ...; case RIGHT: ...;}, компилятор может предупредить меня, что я забыл CENTERрегистр. Это может существенно сэкономить время. На языках без перечислений или без конструкции переключателя это можно смоделировать с помощью шаблона посетителя, хотя это более полезно при наличии статической типизации.

Другое преимущество состоит в том, что перечисления могут рассматриваться как отдельный тип. Например, я могу объявить, что метод принимает HAlignmentпараметр, а не любое целое число. Затем код не будет компилироваться, если я предоставлю что-либо, кроме одного из трех возможных значений HAlignment. Однако перечисления C плохо инкапсулированы, и константы перечисления могут использоваться взаимозаменяемо с целыми числами. Другие языки здесь строже.

В JavaScript мы не получаем ни одного из этих преимуществ. В данном примере объявляется объект, который обрабатывается как перечисление. Это имеет некоторые преимущества для программиста, например, облегчает документирование, группирует все «константы» в один объект,…. Тем не менее, это просто соглашение, что такой объект подобен перечислению.

Дело в том, что HTML имеет только конечный и известный набор тегов. Вы можете взглянуть на спецификацию HTML5 и вставить эти имена элементов в код как перечисление, и, следовательно, усложнить внедрение <blink>тега в вашу программу. Лучше закодировать эти знания в одном месте, чтобы засорять ваш код специальными строковыми литералами (или, что еще хуже, магическими числами).

Амон
источник
В таком случае, если я перейду <blink>к какому-либо методу в javascript, ничто не сможет остановить меня, верно? но в java
здравии вылезает
@CodeYogi да, потому что JS не имеет статической системы типов и, в частности, не имеет понятия перечислимых типов. Тем не менее, я могу задокументировать параметр метода как «принимает имя тега», что приведет к тому, что программист вызовет его, foo(TagName.STRONG)что немного лучше. Было бы еще лучше, если бы JS пожаловался, если поле не существует, но здесь мы получим только, undefinedесли я попытаюсь TagName.BLINK. В JS это ничего не стоит, но это начало.
Амон
Хм, кодовая ссылка, о которой я упоминал выше, использует компилятор замыкания, поэтому здесь имеет смысл.
CodeYogi
Clojure - это функциональный язык, поэтому я не уверен, насколько ООП относится к этому вопросу, но, кроме этого, важно различать перечисления, которые, как правило, представляют собой просто набор целых чисел (а не ОО), и шаблон 'Typesafe enum', который является ОО. и что поддерживает Java.
JimmyJames
@JimmyJames Я говорю о JS, а не о Clo J Юр (который работает на платформе Java, а также поддерживает ООП в некоторой степени). Вопрос был помечен oop , поэтому я упоминаю об этом в начале. Я не очень понимаю , как типизированные перечисления связаны с ООП, это просто особенность системы типа (много языков , не ООП имеют системы типа :-))
Амон
3

Даже если ваш язык не требует компиляции, вы, вероятно, будете использовать какую-то среду IDE или инструменты разработки, которые могут дать гораздо лучшую поддержку для чего-то вроде enum, чем просто для строк.

Например, если вы используете объектный литерал типа enum в javascript, ваш редактор сообщит вам о завершении кода, а программа проверки кода, такая как JSHint или JSLint, предупредит вас, если вы случайно используете неправильное значение.

hansmaad
источник
Я думаю, что многие другие ответы или пропускают или бьют вокруг этого пункта. Использование 'emum' в динамическом языке может ничего не сделать для компилятора, но оно действительно может помочь некоторым IDE, инструментам документации, а также не забывать людей, которые пытаются понять код.
Роберт
2

Смысл такого перечисления может состоять в том, чтобы предоставить Js Api (goog) набор / набор разрешенных тегов. Какие? Те, которые определены в W3C HTML 4.01 ( ознакомьтесь с документацией enum ). Так что это настройки границ.

Может быть, а может и не быть настоящей целью, однако для этой цели она отлично работает.

Если вы знаете, как работает Javascript, код выполняет определение массива, индексированного по строкам :-). Какое-либо значение является строкой, но это может быть любой другой компонент с атрибутами, функциями и т. Д. Пусть ваше воображение будет свободным, и вы увидите преимущества везде.

Помимо Javascript, я часто использую перечисления для моделирования и управления конечными автоматами .

START> IN_PROGRESS> ПОДТВЕРЖДЕНО> ЗАВЕРШЕНО> ...

В java switch позволяет перечисления, так что довольно легко проверять состояния в конечный автомат , циклически проходить по всему перечислению, определять приоритеты, выполняя сложные перечисления, ...

Я также использую их для определения типизированных и немодифицируемых констант:

  • Да нет

Также сложные перечисления (что позволяет делать безопасные преобразования / парсеры)

  • Да (1, верно), Нет (0, неверно)

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

Что перечисление дает (среди прочего), это границы и типизация

LAIV
источник