1.Строки.Префиксы, суффиксы, подстроки. Языки.
Строка – это конечная последовательность символов а1, а2,…,аn, каж-й из кот-х принадлежит некоторому конечному алф-ту Σ, при этом символы в строке могут повторяться.
Пустой строкой наз-т ε-строку ее длина-ноль, т.е.без единого символа.(не=пробелу). |x|=m-длина строки, т.е.строка содержит m символов.
Пусть Σ-некот-й алф-т, обозначим Σ * мн-во опред-х над этим алф-м строк. Для Σ=<0,1>; Σ * = <ε,0,1,01,11,10,101,…>видно, что н-во Σ * — предс-т собой бесконечное счетное мн-во элем-в, ε-строка всегда Σ *
Пусть сущ-т строка х Σ * и |x|=m
Пусть сущ-т строка y Σ * и |y|=n, тогда объединение строк ху им.длину |xy|=m+n – конкатенация.
Если некоторая срока z м.б.представлена как объединение строк х и у: z=ху, то строку х наз-т префиксом строки z, а строку у-суффиксом. Если строка z т.ч.ее м/о представить как объединение 3х строк z=xwy, то строка w н-ся подстрокой строки z.
Разв-е теории и ср-в искус.интелекта позволяет надеяться на то, что взаимод-е чел-ка и ком-ра в недалеком будущем буд/т осуществляться на языке, близком к естественному. Но в наст.время, прог-ты в основном описывают задачи на формальных языках, на языках высокого уровня и иногда на ассемблере. Прог-мы, написанные на алгоритмических языках становятся доступными ком-ру, т/о после их трансляции, т.е.преобразования команд выс.ур/ня в машинные инструкции. Теория построения трансляторов базируется на теории формальнх языков, особенно в части синтакс. и семантического разбора. (семантика – смысл, синтаксис – грамматика).
Формальным языком L над алф-ом Σ н-ся произвольное подмн-во мн-ва Σ * .
Если L1 и L2 это 2а формальных языка, то их объединение есть нов.форм.язык, т.ч.L= L1L2
L 0 = ε, L 1 =L, L 2 =L*L -объединение форм.языка L с самим собой:
Замыкание Клини форм.языка L н-ся .Тогда
, тогдаL * =L + U<ε>, анологично, можно записать замыкание Клини для мн-ва строк.
2. Форма Бэкуса-Наура. Дерево вывода. Синтакс-е и семан-е деревья.
Правила, определяющие мн-ва текстов образ-т сиснтаксис языка, а описание мн-ва смыслов и соответствий м/у текстами и смыслами – семантику языка. Если в ест.языке допуск-ся некорректности в синтаксисе и м.б.понятен смысл предложения, то в формальных языках предложение в первую очередь должно быть правильным синтаксически.
Ф-ла Бэкуса-Наура(БНФ) исп-ся для описания синтаксиса языков прогр-ия, она использует след-щие 4 символа:
::= присвоить; 2) < — открыть; 3) > — закрыть; 4) | — или
//The man drives a car.
<простое предложение>::=<подфраза сущ-го><глагол><подфраза сущ-го>;
Связи, задаваемые ф-лой Б-Н м.б.представлены и графически в виде дерева-вывода:
м/о построить мн-во простых предложений, удовлетворяющих дан.структуре и синтаксически правильных, но не все они буд.им.смысл.( The car drives a man).
Разбор арифмет-го выражения.
F→a|b|c|(E).
Литералы
Последовательность символов, представляющая постоянные значения, хранящиеся в переменных, называется литералом.
Литерал — это представление значения в исходном коде, например число или строка.
Стандартные литералы
Swift предоставляет следующие типы литералов:
Название | Предполагаемый тип по умолчанию | Пример |
---|---|---|
Integer | Int | 123, 0b1010, 0o644, 0xFF |
Floating-Point | Double | 3.14, 6.02e23, 0xAp-2 |
String | String | “Hello”, “”” . . . “”” |
Extended Grapheme Cluster | Character | “A”, “é”, “” |
Unicode Scalar | Unicode.Scalar | “A”, “´”, “\u<1F1FA>” |
Boolean | Bool | true, false |
Nil | Optional | nil |
Array | Array | [1, 2, 3], [“Den”, “Bob”] |
Dictionary | Dictionary | [“a”: 1, “b”: 2] |
Самое важное, что нужно понять о литералах в Swift, это то, что они определяют значение, но не определенный тип.
Когда компилятор встречает литерал, он пытается автоматически определить тип. Он делает это, ища каждый тип, который может быть инициализирован таким литералом, и сужая его на основе любых других ограничений.
Если ни один тип не может быть выведен, Swift инициализирует тип по умолчанию для этого вида литералов — Int для целочисленного литерала, String для строкового литерала и т.д.:
В случае nil литералов тип никогда не может быть выведен автоматически и поэтому должен быть объявлен:
Для литералов массивов и словарей связанные типы для коллекции выводятся на основе ее содержимого. Однако вывод типов для больших или вложенных коллекций — сложная операция, которая может значительно увеличить время, необходимое для компиляции кода. Вы можете ускорить процесс, добавив явный тип в свое объявление:
Целочисленные литералы
Целочисленный литерал (Integer literals) может быть десятичной, двоичной, восьмеричной или шестнадцатеричной константой.
- Десятичные литералы (Decimal literals): Каждое значение, объявленное в целочисленном литерале, имеет десятичный тип. Следовательно, ему не предшествует какое-либо число или символ, как в приведенных выше двоичных литералах.
- Двоичные литералы (Binary literals): начинается с префикса 0b . Он представляет двоичные значения.
- Восьмеричные литералы (Octal literals): начинаются с префикса 0o . Он используется для представления восьмеричных значений.
- Шестнадцатеричные литералы (Hexadecimal literals): начинаются с префикса 0x . Он используется для представления шестнадцатеричных значений.
Десятичные литералы содержат цифры от 0 до 9 . Двоичные литералы содержат 0 и 1 , восьмеричные литералы содержат от 0 до 7 , а шестнадцатеричные литералы содержат от 0 до 9 , а также от A до F в верхнем или нижнем регистре.
Отрицательные целые литералы выражаются путем добавления знака минус ( — ) перед целочисленным литералом, как в -42 .
Символы подчеркивания ( _ ) разрешены между цифрами для удобства чтения, но они игнорируются и поэтому не влияют на значение литерала. Целочисленные литералы могут начинаться с ведущих нулей ( 0 ), но они также игнорируются и не влияют на основание или значение литерала.
Если не указано иное, предполагаемым типом целочисленного литерала по умолчанию является тип Int стандартной библиотеки Swift.
Вот несколько примеров целочисленных литералов:
Литералы с плавающей точкой
Литерал с плавающей точкой (Floating point literals) имеет целочисленную часть, десятичную точку, дробную часть и экспоненту. Вы можете представлять литералы с плавающей точкой в десятичной или шестнадцатеричной форме.
По умолчанию литералы с плавающей запятой выражаются в десятичном виде (без префикса), но они также могут быть выражены в шестнадцатеричном виде (с префиксом 0x):
- Десятичные литералы с плавающей точкой (Decimal floating-point literals) состоят из последовательности десятичных цифр, за которыми следует либо десятичная дробь, либо десятичный показатель степени, либо и то, и другое. Десятичная дробь состоит из десятичной точки ( . ), за которой следует последовательность десятичных цифр. Показатель степени состоит из префикса e в верхнем или нижнем регистре, за которым следует последовательность десятичных цифр, указывающая, на какую степень числа 10 умножается значение, предшествующее e . Например, 1,25e2 представляет 1,25 x 10^2 , что равно 125,0 . Точно так же 1,25e-2 представляет собой 1,25 x 10^-2 , что равно 0,0125 .
- Шестнадцатеричные литералы с плавающей точкой (Hexadecimal floating-point literals) состоят из префикса 0x , за которым следует необязательная шестнадцатеричная дробь, за которой следует шестнадцатеричный показатель степени. Шестнадцатеричная дробь состоит из десятичной точки, за которой следует последовательность шестнадцатеричных цифр. Показатель степени состоит из префикса p в верхнем или нижнем регистре, за которым следует последовательность десятичных цифр, указывающая, на какую степень числа 2 умножается значение, предшествующее p . Например, 0xFp2 представляет 15 x 2^2 , что равно 60 . Точно так же 0xFp-2 представляет 15 x 2^-2 , что дает 3,75 .
Отрицательные литералы с плавающей запятой выражаются путем добавления знака минус ( — ) перед литералом с плавающей запятой, как в -42.5 .
Символы подчеркивания ( _ ) допускаются между цифрами для удобства чтения, но они игнорируются и поэтому не влияют на значение литерала. Литералы с плавающей запятой могут начинаться с ведущих нулей ( 0 ), но они также игнорируются и не влияют на основание или значение литерала.
Если не указано иное, предполагаемым типом литерала с плавающей запятой по умолчанию является тип Double стандартной библиотеки Swift, который представляет 64-битное число с плавающей запятой. Стандартная библиотека Swift также определяет тип Float , который представляет 32-битное число с плавающей запятой.
Вот несколько примеров литералов с плавающей точкой:
Строковые литералы
Строковый литерал (String literal) — это последовательность символов, заключенная в начальную двойную кавычку и закрывающую двойную кавычку.
Разница между строковым (String) и символьным (Character) литералом заключается в том, что строковый литерал содержит последовательность символов, а символьный литерал содержит один символ. Пример показан ниже:
Предполагаемый тип строкового литерала по умолчанию — String .
Многострочные литералы строк
Если вам нужно создать строку, которая поддерживает многострочный вид, используйте литерал многострочной строки — последовательность символов, обернутых в три двойные кавычки ( «»» ):
Многострочный литерал строки включает в себя все строки между открывающими и закрывающими кавычками. Строка начинается на первой строке после открывающих кавычек ( «»» ), а заканчивается на строке предшествующей закрывающим кавычкам ( «»» ), что означает, что ни одна из строк ниже ни начинается, ни заканчивается символом переноса строки:
Когда ваш исходный код включает в себя символ переноса строки внутри литерала многострочной строки, то этот символ переноса строки так же появляется уже внутри значения этой строки.
Если вы хотите использовать символ переноса строки для того, чтобы сделать ваш код более читаемым, но вы не хотите чтобы символ переноса строки отображался в качестве части значения строки, то вам нужно использовать символ обратного слэша ( \ ) в конце этих строк:
Для того, чтобы создать литерал строки, который начинается и заканчивается символом возврата каретки ( \r ), напишите пустую строчку в самом начале и в конце литерала строки, например:
Многострочная строка может иметь отступы для соответствия окружающему ее коду. Пробел до закрывающей группы двойных кавычек ( «»» ) сообщает Swift, сколько пробелов нужно игнорировать в начале каждой строки. Если же вы напишите дополнительные пробелы напротив какой-либо строки к тем, которые стоят напротив закрывающих кавычек, то эти дополнительные пробелы уже будут включены в значение строки.
В примере выше, не смотря на то, что весь литерал многострочной строки имеет отступ, первая и последняя строка будут начинаться без пробелов. Средняя же строка будет иметь отступ, так как она начинается с дополнительными четырьмя пробелами относительно закрывающей группы двойных кавычек.
Специальные символы в строковых литералах
Специальные символы используются в строковых литералах для формирования изменений строковых литералов, известной как управляющая последовательность (escape sequence).
Строковые литералы не могут содержать неэкранированные двойные кавычки ( “ ), неэкранированную обратную косую черту ( \ ), возврат каретки или перевод строки.
Экранирование осуществляется путём добавления обратной косой черты ( \ ) перед экранируемым символом.
Строковые литералы могут включать в себя следующие специальные символы:
- экранированные специальные символы
- \0 (нулевой символ — Null character),
- \\ (обратный слэш — Backslash),
- \t (горизонтальная табуляция — Horizontal tab),
- \n (новая строка — Line feed),
- \r (возвращение каретки — Carriage return),
- \» (двойные кавычки — Double quotation mark),
- \’ (одиночные кавычки — Single quotation mark),
Приведенный ниже код показывает все эти четыре примера специальных символов.
- wiseWords константа содержит два экранированных символа: двойные кавычки,
- DollarSign , blackHeart и sparklingHeart константы показывают скалярный формат Юникода:
Так как многострочные строки имеют три двойные кавычки вместо одной, то вы можете включить двойную кавычку внутрь многострочной строки без знака экранирования. Для того, чтобы включить символы «»» в многострочную строку, вам нужно экранировать хотя бы одну из кавычек, например:
Интерполяция и конкатенация строк
Значение выражения можно вставить в строковый литерал, поместив выражение в круглые скобки после обратной косой черты ( \ ). Это называется интерполяция. Интерполированное выражение может содержать строковый литерал, но не может содержать неэкранированную обратную косую черту, возврат каретки или перевод строки.
В этом примере все строковые литералы имеют одинаковое значение — «1 2 3» .
Строковые литералы, объединенные оператором + , объединяются во время компиляции (compile time). Это называется конкатенация (объединение) строк. Например, значения textA и textB в приведенном ниже примере идентичны — конкатенация выполняется не во время выполнения (runtime).
Необработанные строковые литералы (Raw String Literals)
Необработанные строки позволяют нам отключить все динамические функции строковых литералов (такие как интерполяция и интерпретация специальных символов, таких как \n ), в пользу простого обращения с литералом, как с необработанной последовательностью символов. Необработанные строки определяются путем окружения строкового литерала знаками решетки # (хэш-символами или «хэштегами», как их называют дети):
https://amdy.su/wp-admin/options-general.php?page=ad-inserter.php#tab-8Строка, разделенная расширенными разделителями, представляет собой последовательность символов, заключенных в кавычки и сбалансированный набор из одного или нескольких знаков решетки (number signs) — # . Строка, разделенная расширенными разделителями, имеет следующие формы:
Специальные символы в строке, разделенной расширенными разделителями, отображаются в результирующей строке как обычные символы, а не как специальные символы. Вы можете использовать расширенные разделители для создания строк с символами, которые обычно имеют особый эффект, такой как генерация интерполяции строк, запуск управляющей последовательности или завершение строки.
В следующем примере показан строковый литерал и строка, разделенная расширенными разделителями, которые создают эквивалентные строковые значения:
Хотя эта особенность, которая теоретически никогда не должна быть нужна, но можно добавить больше хеш-символов вокруг вашей строки, чтобы сделать более уникальные разделители строк.
Например, все они создают одну и ту же строку:
Причина, по которой это существует, заключается в том, что строки заканчиваются только тогда, когда вы этого хотите, поэтому в маловероятном случае, когда вам нужно написать «# в строке, вы не столкнетесь с проблемами.
Например, чтобы решить задачу, вам нужно написать строку типа My dog said «woof»#gooddog . Здесь не оставлено пробела после кавычки в слове “гав” и сразу же использовал хэш-символ. Используя необработанную строку с одинарным разделителем, Swift увидит это как признак конца строки, поэтому вместо этого вам нужно будет написать это:
Если вы используете более одного знака # для формирования строки, разделенной расширенными разделителями, не размещайте пробелы между знаками # :
Многострочные строковые литералы, создаваемые с помощью расширенных разделителей, имеют те же требования к отступам, что и обычные многострочные строковые литералы.
Чем полезны необработанные строки?
Предложение Swift Evolution для необработанных строк содержит три примера того, где необработанные строки являются хорошей идеей. В частности, код, который:
- Заменяется экранирование. Экранирование активно вредит просмотру и проверке кода.
- Уже экранировано. Экранированный материал не должен предварительно интерпретироваться компилятором.
- Требуется легкий перенос между исходным кодом и кодом в обоих направлениях, будь то тестирование или просто обновление исходного кода.
В качестве примера рассмотрим регулярные выражения. Представьте, что у нас есть такая строка:
В этом примере используются необработанные строки, чтобы мы могли показать, как выглядит интерполяция строк, а не использовать ее на самом деле — строка \(age) появится в тексте, а не будет заменена значением переменной с именем age .
Необработанные строковые литералы особенно полезны, когда мы хотим встроить строки, которые должны содержать специальные символы, такие как кавычки или обратную косую черту.
Вот еще один пример, связанный с тестами, в котором мы используем необработанный строковый литерал для определения строки JSON для кодирования экземпляра пользователя:
В то время как необработанные строки по умолчанию отключают такие функции, как интерполяция строк, есть способ переопределить это, добавив еще один знак решетки сразу после обратной косой черты, ведущей к интерполяции. Например, если вы хотите использовать интерполяцию строк, теперь вам следует использовать \#(имя_переменной) , а не просто \(имя_переменной) , например:
Вы также можете использовать их с многострочными строками, например:
Наконец, необработанные строки также особенно полезны при интерпретации строки с использованием определенного синтаксиса, особенно если этот синтаксис в значительной степени зависит от символов, которые обычно необходимо экранировать в строковом литерале, например, в регулярных выражениях. Определяя регулярные выражения с использованием необработанных строк, экранирование не требуется, что дает нам выражения, которые настолько удобочитаемы, насколько они могут быть получены:
Логические литералы
** Логические (Булевы) литералы** (Boolean literals) бывают двух типов:
- Значение true , представляющее истину.
- Значение false , представляющее ложь.
Nil литерал
Nil литерал имеет одно значение nil , представляющее отсутствие значения.
Литералы в Playgrounds
Помимо стандартных литералов, перечисленных выше, есть несколько дополнительных типов литералов для кода в Playgrounds:
Название Предполагаемый тип по умолчанию Пример Color NSColor / UIColor #colorLiteral(red: 1, green: 0, blue: 1, alpha: 1) Image NSImage / UIImage #imageLiteral(resourceName: “icon”) File URL #fileLiteral(resourceName: “articles.json”) В Xcode или Swift Playgrounds на iPad эти литеральные выражения автоматически заменяются интерактивным элементом управления, который обеспечивает визуальное представление указанного цвета, изображения или файла.
Этот элемент управления также упрощает выбор новых значений: вместо ввода значений RGBA или путей к файлам вам предоставляется палитра цветов или селектор файлов.
В большинстве языков программирования есть литералы для логических значений, чисел и строк, а во многих есть литералы для массивов, словарей и регулярных выражений.
Сокращение этих основных строительных блоков упрощает чтение и написание кода.
Как работают литералы
Литералы похожи на слова: их значение может меняться в зависимости от окружающего контекста.
В приведенном выше примере мы видим, что литерал массива, содержащий строковые литералы, по умолчанию инициализируется массивом строк. Однако, если мы явно приводим первый элемент массива к типу Character , литерал инициализируется как массив символов. В качестве альтернативы, мы могли бы преобразовать все выражение в Set<Character> , чтобы инициализировать набор символов.
Как это работает?
В Swift компилятор решает, как инициализировать литералы, просматривая все видимые типы, реализующие соответствующий протокол литеральных выражений (literal expression protocol).
- ExpressibleByStringLiteral для строковых литералов,
- ExpressibleByUnicodeScalarLiteral для строковых литералов, содержащих только один скаляр Unicode,
- ExpressibleByExtendedGraphemeClusterLiteral для строковых литералов, содержащих только один расширенный кластер графем.
Чтобы соответствовать протоколу, тип должен реализовать требуемый инициализатор. Например, для протокола ExpressibleByIntegerLiteral требуется init(integerLiteral:) .
Что действительно хорошо в этом подходе, так это то, что он позволяет вам добавлять инициализацию литералов для ваших собственных пользовательских типов.
Поддержка инициализации литералов для пользовательских типов
Поддержка инициализации с помощью литералов, когда это уместно, может значительно улучшить эргономику пользовательских типов, заставляя их чувствовать себя встроенными.
Например, если вы хотите поддерживать нечеткую логику (англ. fuzzy logic), в дополнение к стандартным булевым значениям, вы можете реализовать Fuzzy тип следующим образом:
Нечеткое значение (Fuzzy value) представляет собой значение истинности, которое колеблется от полностью истинного до полностью ложного в числовом диапазоне от 0 до 1 (включительно). То есть значение 1 означает абсолютно верно, 0,8 — в основном верно, а 0,1 — в основном неверно.
Для более удобной работы со стандартной булевой логикой мы можем расширить Fuzzy , приняв протокол ExpressibleByBooleanLiteral :
На практике, не так много ситуаций, в которых уместно инициализировать тип с помощью логических литералов. Поддержка строковых, целочисленных литералов и литералов с плавающей запятой встречается гораздо чаще.
Этот код не меняет значения по умолчанию true или false . Нам не нужно беспокоиться о нарушении существующего кода только потому, что мы ввели концепцию “полуправды” в наш код (“представление действительно выглядело анимированным… может быть?” — “view did appear animated… maybe?”). Единственные ситуации, в которых true или false инициализируют значение Fuzzy , — это когда компилятор может вывести тип как Fuzzy :
Поскольку Fuzzy инициализируется одним значением Double , разумно разрешить инициализацию значений также литералами с плавающей запятой. Трудно представить себе ситуацию, в которой тип поддерживает литералы с плавающей запятой, но не поддерживает целочисленные литералы, поэтому мы должны поступать так же (однако обратное неверно; существует множество типов, которые работают с целыми числами, но не с числами с плавающей точкой):
После принятия этих протоколов тип Fuzzy теперь выглядит и ощущается как полноправный член стандартной библиотеки Swift.
(Теперь осталось только реализовать стандартные логические операторы!)
Если вы хотите оптимизировать удобство и производительность разработчика, вам следует подумать о реализации любых литеральных протоколов, подходящих для ваших пользовательских типов.
Пользовательская интерполяция
В качестве примера предположим, что мы хотим сохранить заданную строку, опционально применив к ней префикс и суффикс. В идеале мы хотели бы просто интерполировать эти значения, чтобы сформировать окончательную строку, например:
Однако, поскольку и префикс, и суффикс являются необязательными (опциональными), простое использование их описания не даст желаемого результата — и компилятор даже выдаст нам предупреждение:
Хотя у нас всегда есть возможность развернуть каждую из этих двух опций перед их интерполяцией, давайте посмотрим, как мы можем сделать обе эти вещи за один раз, используя пользовательскую интерполяцию. Мы начнем с расширения String.StringInterpolation новой перегрузкой appendInterpolation , которая принимает любое необязательное значение:
Приведенная выше метка параметра unwrapping: важна, поскольку именно ее мы будем использовать, чтобы указать компилятору использовать этот конкретный метод интерполяции — например:
Хотя это всего лишь синтаксический сахар (syntactic sugar), вышеприведенное выглядит очень аккуратно! Однако это лишь малая часть того, что могут сделать пользовательские методы интерполяции строк. Они могут быть как универсальными, так и неуниверсальными, принимать любое количество аргументов, использовать значения по умолчанию и многое другое, что могут делать «обычные» методы.
Еще полезные ссылки
Также информацию по литералам можно получить на странице официальной документации.
Это маленькое чудо — алгоритм Кнута-Морриса-Пратта (КМП)
Строки нулей и единиц одинаковы, только в первых двух иллюстрациях индексы с 0, а в следующих — с 1. На самом деле, это не принципально, поскольку в массив пишутся длины подстрок, а способ нумерации символов в строке роли не играет.Последняя иллюстрация — взгляд «с высоты птичьего полета» на префиксы-суффиксы строкиhabrhabhabrhabrhabrhabhabrhabhabrhabhabrhabrhabrhabhabrhabraбез массивов индексов и длин.
Соглашение об именах (программирование) — Naming convention (programming)
В компьютерном программировании , именование представляет собой набор правил для выбора последовательности символов , которые будут использоваться для идентификаторов , которые обозначают переменные , тип , функцию и другие объекты в исходном коде и документации .
Причины использования соглашения об именах (в отличие от разрешения программистам выбирать любую последовательность символов) включают следующее:
- Чтобы уменьшить усилия, необходимые для чтения и понимания исходного кода;
- Чтобы позволить обзорам кода сосредоточиться на вопросах, более важных, чем стандарты синтаксиса и именования.
- Чтобы позволить инструментам проверки качества кода сосредоточить свои отчеты в основном на важных проблемах, помимо синтаксиса и предпочтений стиля.
Выбор соглашения об именах может быть чрезвычайно спорным вопросом, при этом сторонники каждого считают свои лучшие, а другие — худшие. В просторечии говорят, что это вопрос догмы . Многие компании также установили свои собственные соглашения.
СОДЕРЖАНИЕ
Потенциальные преимущества
Некоторые из потенциальных преимуществ, которые можно получить, приняв соглашение об именах, включают следующее:
- для предоставления дополнительной информации (т. е. метаданных ) об использовании идентификатора;
- чтобы помочь формализовать ожидания и обеспечить последовательность в команде разработчиков;
- для обеспечения возможности использования автоматизированного рефакторинга или инструментов поиска и замены с минимальной вероятностью ошибки;
- для повышения ясности в случаях возможной двусмысленности;
- для улучшения эстетического и профессионального внешнего вида продукта работы (например, путем запрета слишком длинных имен, смешных или «симпатичных» имен или сокращений);
- чтобы помочь избежать «конфликтов имен», которые могут возникнуть при объединении рабочего продукта разных организаций (см. также: пространства имен );
- предоставить значимые данные, которые будут использоваться при передаче проекта, что требует предоставления исходного кода программы и всей соответствующей документации;
- чтобы обеспечить лучшее понимание в случае повторного использования кода через длительный промежуток времени.
Вызовы
Выбор соглашений об именах (и степени их соблюдения) часто является спорным вопросом, поскольку сторонники придерживаются своей точки зрения как лучшей, а другие — как низшей. Более того, даже при наличии известных и четко определенных соглашений об именах некоторые организации могут не соблюдать их последовательно, вызывая непоследовательность и путаницу. Эти проблемы могут усугубиться, если правила соглашения об именах внутренне непоследовательны, произвольны, трудны для запоминания или иным образом воспринимаются как более обременительные, чем полезные.
Читаемость
Правильно подобранные идентификаторы значительно упрощают разработчикам и аналитикам понимание того, что делает система и как исправить или расширить исходный код, чтобы применить его для новых нужд.
является синтаксически правильна, его цель не очевидна. Сравните это с:
что подразумевает намерение и значение исходного кода, по крайней мере, для тех, кто знаком с контекстом утверждения.
Эксперименты показывают, что стиль идентификатора влияет на отзыв и точность, а знакомство со стилем ускоряет отзыв.
Общие элементы
Точные правила соглашения об именах зависят от контекста, в котором они используются. Тем не менее, есть несколько общих элементов, которые влияют больше всего, если не на все общепринятые сегодня соглашения об именах.
Длина идентификаторов
Основополагающими элементами всех соглашений об именах являются правила, относящиеся к длине идентификатора (т. Е. Конечному количеству отдельных символов, разрешенных в идентификаторе). Некоторые правила диктуют фиксированную числовую границу, в то время как другие определяют менее точные эвристики или рекомендации.
Правила длины идентификатора обычно оспариваются на практике и являются предметом многочисленных научных дискуссий.
- более короткие идентификаторы могут быть предпочтительнее как более целесообразные, потому что их легче вводить (хотя многие IDE и текстовые редакторы обеспечивают завершение текста, что смягчает это)
- очень короткие идентификаторы (такие как ‘i’ или ‘j’) очень сложно однозначно отличить с помощью инструментов автоматического поиска и замены (хотя это не проблема для инструментов, основанных на регулярных выражениях )
- более длинные идентификаторы могут быть предпочтительнее, потому что короткие идентификаторы не могут закодировать достаточно информации или кажутся слишком загадочными
- более длинные идентификаторы могут быть не в пользу из-за визуального беспорядка
Это открытый вопрос исследования, предпочитают ли некоторые программисты более короткие идентификаторы, потому что их легче набрать или придумать, чем более длинные идентификаторы, или потому, что во многих ситуациях более длинный идентификатор просто загромождает видимый код и не дает ощутимых дополнительных преимуществ.
Краткость в программировании частично объясняется:
- ранние компоновщики, которые требовали, чтобы имена переменных были ограничены до 6 символов для экономии памяти. Более поздний «прогресс» позволил использовать более длинные имена переменных для понимания человеком, но только первые несколько символов были значимыми. В некоторых версиях BASIC, таких как TRS-80 Level 2 Basic, длинные имена были разрешены, но только первые две буквы были значимыми. Эта функция допускала ошибочное поведение, которое было трудно отладить, например, когда имена, такие как «VALUE» и «VAT», использовались и предназначались для различения.
- ранние редакторы исходного кода без автозаполнения
- ранние мониторы с низким разрешением и ограниченной длиной строки (например, всего 80 символов)
- большая часть информатики берет свое начало в математике, где имена переменных традиционно состоят из одной буквы
Регистр букв и цифры
Некоторые соглашения об именах ограничивают отображение букв в верхнем или нижнем регистре. Другие соглашения не ограничивают регистр букв, но дают четко определенную интерпретацию, основанную на регистре букв. Некоторые соглашения об именах определяют, могут ли использоваться буквенные, числовые или буквенно-цифровые символы, и если да, то в какой последовательности.
Идентификаторы из нескольких слов
Распространенная рекомендация — «Используйте значимые идентификаторы». Одно слово может быть не таким значимым или конкретным, как несколько слов. Следовательно, некоторые соглашения об именах определяют правила обработки «составных» идентификаторов, содержащих более одного слова.
Поскольку большинство языков программирования не допускают использования пробелов в идентификаторах, необходим метод разделения каждого слова (чтобы последующим читателям было легче интерпретировать, какие символы принадлежат какому слову). Исторически некоторые ранние языки, особенно FORTRAN (1955) и ALGOL (1958), допускали пробелы в идентификаторах, определяя конец идентификаторов в зависимости от контекста. В более поздних языках от этого отказались из-за сложности токенизации . Можно писать имена, просто объединяя слова, и это иногда используется, например, mypackage для имен пакетов Java, хотя разборчивость страдает от более длинных терминов, поэтому обычно используется какая-то форма разделения.
Слова, разделенные разделителями
Один из подходов — разделить отдельные слова не буквенно-цифровыми символами. Для этой цели обычно используются два символа: дефис («-») и подчеркивание («_»); например, имя из двух слов two words будет представлено как » two-words » или » two_words «. Дефис используется почти всеми программистами, пишущими COBOL (1959), Forth (1970) и Lisp (1958); он также распространен в Unix для команд и пакетов и используется в CSS . У этого соглашения нет стандартного названия, хотя оно может называться lisp-case или COBOL-CASE (сравните Pascal case ), kebab-case , brochette-case или другими вариантами. Из них кебаб-футляр , датируемый по крайней мере 2012 годом, с тех пор приобрел некоторую популярность.
Напротив, языки в традиции FORTRAN / ALGOL, особенно языки семейств C и Pascal , использовали дефис для инфиксного оператора вычитания и не хотели требовать пробелов вокруг него (как языки свободной формы ), предотвращая его использование в идентификаторы. Альтернативой является использование подчеркивания; это распространено в семействе C (включая Python), где слова в нижнем регистре встречаются, например, в языке программирования C (1978) и стали известны как змеиный регистр . Подчеркивания с прописными буквами, как в UPPER_CASE, обычно используются для макросов препроцессора C , отсюда известных как MACRO_CASE, и для переменных среды в Unix, таких как BASH_VERSION в bash . Иногда это с юмором называют SCREAMING_SNAKE_CASE.
Слова, разделенные буквами
Другой подход состоит в том, чтобы указать границы слов, используя средние заглавные буквы, называемые « camelCase », «Pascal case» и многих других имен, таким образом, соответственно передавая « two words » как « twoWords » или « TwoWords ». Это соглашение обычно используется в Pascal , Java , C # и Visual Basic . Обработка инициализмов в идентификаторах (например, « XML » и « HTTP » в XMLHttpRequest ) варьируется. Некоторые диктуют, что они должны быть в нижнем регистре (например XmlHttpRequest ) для облегчения набора текста, читаемости и простоты сегментации , тогда как другие оставляют их в верхнем регистре (например XMLHTTPRequest ) для точности.
Примеры форматов идентификаторов, состоящих из нескольких слов
Форматы идентификаторов, состоящих из нескольких слов
Форматирование Имя (а) twowords плоский чемодан TWOWORDS ВЕРХНИЙ twoWords (нижний) футляр для верблюда, футляр для верблюда TwoWords PascalCase, UpperCamelCase, StudlyCase two_words snake_case , pothole_case TWO_WORDS SCREAMING_SNAKE_CASE , MACRO_CASE, CONSTANT_CASE two_Words верблюд, змея, футляр Two_Words Паскаль, змея, футляр tWo_wORdS sPonGEbOB_cAsE two-words кебаб-кейс , тире-кейс, шепелявый-кейс, спинной-кейс TWO-WORDS ПОЕЗД-ДЕЛО, COBOL-CASE, SCREAMING-KEBAB-CASE Two-Words Обучающий случай, HTTP-заголовок-регистр Метаданные и гибридные соглашения
Некоторые соглашения об именах представляют собой правила или требования, которые выходят за рамки требований конкретного проекта или проблемной области, а вместо этого отражают более широкий комплекс принципов, определенных архитектурой программного обеспечения , базовым языком программирования или другой методологией кросс-проекта.
Венгерская нотация
Возможно, наиболее известной является венгерская нотация , которая кодирует либо назначение («Apps Hungarian»), либо тип («Systems Hungarian») переменной в ее имени. Например, префикс «sz» для переменной szName указывает, что переменная является строкой с завершающим нулем.
Позиционное обозначение
Стиль, используемый для очень коротких (восемь символов и менее), может быть следующим: LCCIIL01, где LC — это приложение (аккредитивы), C — для COBOL, IIL — для конкретного подмножества процессов, а 01 — порядковый номер.
Такое соглашение все еще активно используется в мэйнфреймах, зависящих от JCL, а также встречается в стиле MS-DOS 8.3 (максимум восемь символов с разделителем точки, за которым следует трехсимвольный тип файла).
Составная схема слов (OF Language)
«Язык OF» IBM был задокументирован в руководстве по IMS ( системе управления информацией ).
В нем подробно описана словесная схема PRIME-MODIFIER-CLASS, которая состоит из таких имен, как «CUST-ACT-NO» для обозначения «номера счета клиента».
Слова PRIME предназначались для обозначения основных «сущностей», представляющих интерес для системы.
Слова МОДИФИКАТОР использовались для дополнительного уточнения, уточнения и удобочитаемости.
В идеале слова CLASS были бы очень коротким списком типов данных, относящихся к конкретному приложению. Общие слова CLASS могут быть: NO (номер), ID (идентификатор), TXT (текст), AMT (сумма), QTY (количество), FL (флаг), CD (код), W (работа) и т. Д. На практике доступные слова КЛАССА будут списком из менее чем двух дюжин терминов.
Слова КЛАССА, обычно расположенные справа (суффикс), служили почти той же цели, что и префиксы венгерской нотации .
Назначение слов CLASS, помимо согласованности, состояло в том, чтобы указать программисту тип данных конкретного поля данных. Перед принятием полей типа BOOLEAN (только два значения) FL (флаг) будет указывать на поле только с двумя возможными значениями.
Конкретные языковые соглашения
ActionScript
Adobe Coding Conventions and Best Practices предлагает стандарты наименования для ActionScript , которые в основном соответствуют стандартам ECMAScript . Стиль идентификаторов похож на стиль Java .
В Аде единственный рекомендуемый стиль идентификаторов — это Mixed_Case_With_Underscores .
В диалектах APL между словами используется дельта (Δ), например PERFΔSQUARE (строчные буквы традиционно отсутствовали в старых версиях APL). Если в названии используются подчеркнутые буквы, то вместо них будет использоваться подчеркиваемая дельта-черта (⍙).
C и C ++
В C и C ++ , ключевые слова и стандартные библиотечные идентификаторы в основном в нижнем регистре. В стандартной библиотеке C сокращенные имена являются наиболее распространенными (например, isalnum для функции, проверяющей, является ли символ числом), в то время как стандартная библиотека C ++ часто использует подчеркивание в качестве разделителя слов (например out_of_range ). Идентификаторы, представляющие макросы , по соглашению записываются с использованием только прописных букв и подчеркиваний (это связано с соглашением во многих языках программирования об использовании идентификаторов только в верхнем регистре для констант). Имена, содержащие двойное подчеркивание или начинающиеся с подчеркивания и заглавной буквы, зарезервированы для реализации ( компилятор , стандартная библиотека ) и не должны использоваться (например, __reserved или _Reserved ). Это внешне похоже на строппинг , но семантика различается: подчеркивания являются частью значения идентификатора, а не являются символами кавычек (как строппинг): значение __foo is __foo (зарезервировано), not foo (но в другом пространство имен).
Соглашения об именах C # обычно следуют рекомендациям, опубликованным Microsoft для всех языков .NET (см. Раздел .NET ниже), но компилятор C # не применяет никаких соглашений.
В руководстве Microsoft рекомендует исключительное использование только PascalCase и верблюжьей , причем последний используется только для имен параметров методы и имен переменных метода локальных (включая метод локальных const значений). Специальное исключение для PascalCase сделано для двухбуквенных сокращений, которые начинаются с идентификатора; в этих случаях обе буквы пишутся с заглавной буквы (например, IOStream ); это не относится к более длинным аббревиатурам (например, XmlStream ). Рекомендации далее рекомендуют, чтобы имя , данное interface быть PascalCase предшествует заглавной буквы I , как и в IEnumerable .
В руководстве Microsoft для именования полей являются специфическими для static , public и protected поля; поля, которых нет static и которые имеют другие уровни доступности (например, internal и private ), явно не подпадают под действие рекомендаций. Наиболее распространенной практикой является использование PascalCase для имен всех полей, для тех , которые , за исключением private (и ни const ни static ), которые даны имена, использование верблюжьего предшествовавшие одним подчеркиванием; например _totalCount ,.
Любое имя идентификатора может начинаться с символа коммерческого предложения ( @ ) без каких-либо изменений в значении. То есть оба factor и @factor относятся к одному и тому же объекту. По соглашению этот префикс используется только в тех случаях, когда идентификатор в противном случае был бы либо зарезервированным ключевым словом (например, for и while ), которое не может использоваться в качестве идентификатора без префикса, либо контекстным ключевым словом (например, from и where ), в котором В некоторых случаях префикс не требуется строго (по крайней мере, не при его объявлении; например, хотя объявление dynamic dynamic; является действительным, это обычно будет восприниматься как dynamic @dynamic; немедленное указание читателю, что последнее является именем переменной).
В Go принято использовать символы подчеркивания MixedCaps или mixedCaps подчеркивания для написания многословных имен. При обращении к структурам или функциям первая буква указывает видимость для внешних пакетов. Если сделать первую букву в верхнем регистре, этот фрагмент кода будет экспортирован, а в нижнем регистре он будет использоваться только в пределах текущей области видимости.
Джава
В Java соглашения об именах для идентификаторов были установлены и предложены различными сообществами Java, такими как Sun Microsystems, Netscape, AmbySoft и т. Д. Примеры соглашений об именах, установленных Sun Microsystems, перечислены ниже, где имя в » CamelCase » состоит из одного составного из числа слов, соединенных без пробелов, причем каждое слово — за исключением первого слова — начальная буква заглавными буквами, например «camelCase».
- class Raster <>
- class ImageSprite <>
- run();
- runFast();
- getBackground();
Имена переменных должны быть короткими, но содержательными. Выбор имени переменной должен быть мнемоническим, то есть предназначенным для указания случайному наблюдателю цели его использования. Следует избегать односимвольных имен переменных, за исключением временных «одноразовых» переменных. Общие имена временных переменных: i, j, k, m и n для целых чисел; c, d и e для символов.
- int i;
- char c;
- float myWidth;
- static final int MAX_PARTICIPANTS = 10;
Компиляторы Java не применяют эти правила, но несоблюдение их может привести к путанице и ошибочному коду. Например, widget.expand() и Widget.expand() подразумевают существенно различное поведение: widget.expand() подразумевает вызов метода expand() в экземпляре с именем widget , тогда как Widget.expand() подразумевает вызов статического метода expand() в классе Widget .
Один широко используемый стиль кодирования Java требует, чтобы UpperCamelCase использовался для классов, а lowerCamelCase — для экземпляров и методов . Признавая это использование, некоторые IDE , такие как Eclipse , реализуют ярлыки на основе CamelCase. Например, в функции поддержки содержимого Eclipse ввод только заглавных букв слова CamelCase будет предлагать любое подходящее имя класса или метода (например, ввод «NPE» и активация помощника по содержимому могут предложить NullPointerException ).
Инициализация трех или более букв — CamelCase вместо прописных (например, parseDbmXmlFromIPAddress вместо parseDBMXMLFromIPAddress ). Также можно установить границу из двух или более букв (например parseDbmXmlFromIpAddress ).
JavaScript
Встроенные библиотеки JavaScript используют те же соглашения об именах, что и Java. Типы данных и функции конструктора используют верхний регистр верблюда ( RegExp , TypeError , XMLHttpRequest , DOMObject ), а методы используют нижний регистр верблюда ( getElementById , getElementsByTagNameNS , createCDATASection ). Чтобы быть последовательными, большинство разработчиков JavaScript следуют этим соглашениям. Смотрите также: конвенции Дугласа Крокфорда
Обычной практикой в большинстве диалектов Лиспа является использование дефисов для разделения слов в идентификаторах, таких как with-open-file и make-hash-table . Имена динамических переменных обычно начинаются и заканчиваются звездочками: *map-walls* . Имена Констант отмечены знаками плюс: +map-size+ .
Microsoft .NET рекомендует для большинства идентификаторов UpperCamelCase , также известный как PascalCase . ( Для параметров и переменных рекомендуется использовать lowerCamelCase ) и является общим соглашением для языков .NET. Microsoft также рекомендует не использовать подсказки префиксов типа (также известные как венгерская нотация ). Вместо использования венгерской нотации рекомендуется заканчивать имя именем базового класса; вместо . LoginButton BtnLogin
Цель-C
Objective-C имеет общий стиль кодирования, уходящий корнями в Smalltalk .
Сущности верхнего уровня, включая классы, протоколы, категории, а также конструкции C, которые используются в программах Objective-C, таких как глобальные переменные и функции, находятся в UpperCamelCase с коротким префиксом верхнего регистра, обозначающим пространство имен, например NSString , UIAppDelegate , NSApp или CGRectMake . Константы могут дополнительно начинаться строчной буквой «k», например kCFBooleanTrue .
Переменные экземпляра объекта используют lowerCamelCase с префиксом подчеркивания, например _delegate и _tableView .
Имена методов используют несколько частей lowerCamelCase разделенных двоеточием , что аргументы разграничить, например: применение: didFinishLaunchingWithOptions: , stringWithFormat: и isRunning .
Паскаль, Модула-2 и Оберон
Виртовские языки Паскаль, Модула-2 и Оберон обычно используют идентификаторы Capitalized или UpperCamelCase для программ, модулей, констант, типов и процедур, lowercase или lowerCamelCase идентификаторы для математических констант, переменных, формальных параметров и функций. В то время как некоторые диалекты поддерживают символы подчеркивания и доллара в идентификаторах, регистр змейки и регистр макроса, скорее всего, ограничены использованием в интерфейсах внешнего API.
Perl берет некоторые подсказки из своего наследия C для условностей. Имена переменных и подпрограмм с локальной областью видимости пишутся строчными буквами с инфиксными символами подчеркивания. Подпрограммы и переменные, которые должны рассматриваться как частные, имеют префикс с подчеркиванием. Переменные пакета заключены в заголовок. Все объявленные константы заглавными. Имена пакетов записываются в верблюжьем регистре, за исключением прагмат, например, strict и mro — строчных букв .
Рекомендации PHP содержатся в PSR-1 ( стандартная рекомендация PHP 1) и PSR-12. Согласно PSR-1, имена классов должны быть в PascalCase, константы классов должны быть в MACRO_CASE, а имена функций и методов должны быть в camelCase.
Python и Ruby
И Python, и Ruby рекомендуют UpperCamelCase использовать имена классов, CAPITALIZED_WITH_UNDERSCORES константы и lowercase_separated_by_underscores другие имена.
В Python, если имя должно быть « частным », оно предваряется одним или двумя символами подчеркивания (в Python это более или менее взлом). Частные переменные применяются в Python только по соглашению. Имена также могут иметь суффикс с подчеркиванием, чтобы предотвратить конфликт с ключевыми словами Python. Префикс с двойным подчеркиванием изменяет поведение классов в отношении искажения имен . Префикс и суффикс с двойным подчеркиванием зарезервированы для «магических имен», которые выполняют особое поведение в объектах Python.
Хотя официального руководства по стилю для R нет, руководство по стилю tidyverse от R-гуру Хэдли Уикхема устанавливает стандарт для большинства пользователей. В этом руководстве рекомендуется избегать использования специальных символов в именах файлов и использовать только цифры, буквы и символы подчеркивания для имен переменных и функций, например fit_models.R.
Raku следует более или менее тем же соглашениям, что и Perl, за исключением того, что он позволяет использовать инфиксный дефис — или апостроф (или одинарную кавычку) внутри идентификатора (но не двух подряд), при условии, что за ним следует буквенный символ. Таким образом, программисты Raku часто используют падеж кебаба в своих идентификаторах; например, fish-food и don’t-do-that являются действительными идентификаторами.
Ржавчина
Rust рекомендует UpperCamelCase использовать псевдонимы типов и имена вариантов struct, trait, enum и enum, SCREAMING_SNAKE_CASE для констант или статики, а также snake_case для имен переменных, функций и структур.
Быстрый
Swift меняет свои соглашения об именах с каждым отдельным выпуском. Однако крупное обновление Swift 3.0 стабилизировало соглашения об именах для lowerCamelCase переменных и объявлений функций. Константы обычно определяются перечисляемыми типами или постоянными параметрами, которые также записываются таким же образом. Объявления классов и других типов объектов UpperCamelCase .
Начиная с Swift 3.0, были сформулированы четкие инструкции по именованию для языка с целью стандартизации соглашений об именах и объявлениях API для всех сторонних API.