авторефераты диссертаций БЕСПЛАТНАЯ БИБЛИОТЕКА РОССИИ

КОНФЕРЕНЦИИ, КНИГИ, ПОСОБИЯ, НАУЧНЫЕ ИЗДАНИЯ

<< ГЛАВНАЯ
АГРОИНЖЕНЕРИЯ
АСТРОНОМИЯ
БЕЗОПАСНОСТЬ
БИОЛОГИЯ
ЗЕМЛЯ
ИНФОРМАТИКА
ИСКУССТВОВЕДЕНИЕ
ИСТОРИЯ
КУЛЬТУРОЛОГИЯ
МАШИНОСТРОЕНИЕ
МЕДИЦИНА
МЕТАЛЛУРГИЯ
МЕХАНИКА
ПЕДАГОГИКА
ПОЛИТИКА
ПРИБОРОСТРОЕНИЕ
ПРОДОВОЛЬСТВИЕ
ПСИХОЛОГИЯ
РАДИОТЕХНИКА
СЕЛЬСКОЕ ХОЗЯЙСТВО
СОЦИОЛОГИЯ
СТРОИТЕЛЬСТВО
ТЕХНИЧЕСКИЕ НАУКИ
ТРАНСПОРТ
ФАРМАЦЕВТИКА
ФИЗИКА
ФИЗИОЛОГИЯ
ФИЛОЛОГИЯ
ФИЛОСОФИЯ
ХИМИЯ
ЭКОНОМИКА
ЭЛЕКТРОТЕХНИКА
ЭНЕРГЕТИКА
ЮРИСПРУДЕНЦИЯ
ЯЗЫКОЗНАНИЕ
РАЗНОЕ
КОНТАКТЫ


Pages:   || 2 | 3 | 4 | 5 |   ...   | 15 |
-- [ Страница 1 ] --

АНДРЕЙ

АЛЕКСАНДРЕСКУ

Язык

программирования

D

16 лет вместе

с профессионалами

The D Programming

Language

Andrei Alexandrescu

HIGH T EС H

Язык программирования

D

Андрей Александреску

Серия «High tech»

А н д р е й А лександреску

Язык программирования D

Перевод H. Данилиной Главный редактор А. Галунов Зав. редакцией H. Макарова Научные редакторы И. Степанов В. Пантелеев Редактор Т. Темкина Корректор О. Макарова Верстка Д. Орлова Александреску А.

Язык программирования D. - Пер. с англ. - СПб.: Символ-Плюс, 2012. 536 c., ил.

ISBN 978-5-93286-205- D - это язык программирования, цель которого - помочь программистам спра­ виться с непростыми современными проблемами разработки программного обеспечения. Он создает все условия для организации взаимодействия моду­ лей через точные интерфейсы, поддерживает целую федерацию тесно взаимо­ связанных парадигм программирования (императивное, объектно-ориентиро ванное, функциональное и метапрограммирование), обеспечивает изоляцию потоков, модульную безопасность типов, предоставляет рациональную модель памяти и многое другое.

«Язык программирования D» - это введение в D, автору которого можно до­ верять. Это книга в фирменном стиле Александреску - она написана нефор­ мальным языком, но без лишних слов и не в ущерб точности. Андрей рас­ сказывает о выражениях и инструкциях, о функциях, контрактах, модулях и о многом другом, что есть в языке D. В книге вы найдете полный перечень средств языка с объяснениями и наглядными примерами;

описание поддержки разных парадигм программирования конкретными средствами языка D;

ин­ формацию о том, почему в язык включено то или иное средство, и советы по их использованию;

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

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

ISBN 978-5-93286-205- ISBN 978-0-321-63536-5 (англ) © Издательство Символ-Плюс, Authorized translation of the English edition © 2010 Pearson Education, Inc. This translation is published and sold by permission of Pearson Education, Inc., the owner of all rights to publish and sell the same.

Все права на данное издание защищены Законодательством РФ, включая право на полное или час­ тичное воспроизведение в любой форме. Все товарные энаки или зарегистрированные товарные зна­ ки, упоминаемые в настоящем издании, являются собственностью соответствующих фирм.

Издательство «Символ-Плюс». 199034, Санкт-Петербург, 16 линия, 7, тел. (812) 380-5007, www.symbol.ru. Лицензия ЛП N 000054 от 25.12.98.

Подписано в печать 16.04.2012. Формат 70x100 У 1е»

Печать офсетная. Объем 33,5 печ. л.

Отпечатано в цифровом типографии «Буки Всдн» на оборудовании Konica MinolLi ООО «Ваш полиграфический партнер», ул. Ильмснский пр-д. д. 1, корп. Тел.: (495) 926-63-96, w w w.bukivedi.com,info@bukivedi.com. Заказ № 1298.

Оглавление О бавторе. П редисловие Уолтера Брайта....................... П редисловие Скотта М ей ер са.. П редисловие научных р ед акто р о в п ер ево д а.. Введение.................... 1.3 н а к о м с т в о с я зы к о м 0..................................... 1.1. Числа и вы ражения............ 1.2. Инструкции... 1.3.0сновы работы сф ункциями. 1.4.Массивыиассоциативныемассивы. 1.4.1.Работаемсословарем.............. 1.4.2. Получение среза массива. Функции с обобщенными типами параметров. Тесты модулей... 1.4.3.Подсчетчастот.Лямбда-функции. 1.5.0сновны еструктуры данны х.. 1.6.Интерфейсы иклассы. 1.6.1.Больш естатистики.Наследование.................. 1.7. Значения против ссылок.......... 1.8. Итоги...... 2. Основные типы данны х. Выражения... 2.1.Идентификаторы. 2.1.1.Ключевыеслова. 2.2.Литералы. 2.2.1. Логические литералы.. 2.2.2.Ц елы елитералы. 2.2.3.Л итералы сплаваю щ ейзапятой.... 2.2.4.3наковыелитералы................... 2.2.5.Строковыелитералы.. 2.2.6. Литералы массивов и ассоциативных массивов.. 2.2.7. Функциональные литералы..... 2.3. Операции........................... 2.3.1. L-значения и г-значения.. 2.3.2.Неявныепреобразованиячисел.......... 6 Оглавление 2.3.3. Типы числовых операций. 2.3.4.Первичныевы ражения. 2.3.5. Постфиксные операции. 2.3.6.Унарны еоперации. 2.3.7. Возведение в степень.. 2.3.8. Мультипликативныеоперации.. 2.3.9.А ддитивны еоперации. 2.3.10. Сдвиг. 2.3.11.В ы раж ен ияш.. 2.3.12.С равнение.. 2.3.13. Поразрядные ИЛИ, ИСКЛЮЧАЮЩЕЕ ИЛИ и И.. 2.3.14.Л огическоеИ. 2.3.15.Л огическоеИ Л И. 2.3.16.Тернарнаяусловнаяоперация.. 2.3.17.Присваивание.. 2.3.18. Выражения с запятой.. 2.4. Итоги и справочник.. 3. Инструкции. 3.1. Инструкция-выражение 3.2. Составная инструкция. 3.3. Инструкция i f........................... 3.4. Инструкция static if. 3.5.HHCTpyK4HHSwitch. 3.6. Инструкция final switch. 3.7. Циклы... 3.7.1. Инструкция while (цикл с предусловием). 3.7.2. Инструкция do-while (цикл с постусловием).. 3.7.3. Инструкция for (цикл со счетчиком)... 3.7.4. Инструкция foreach (цикл просмотра).. 3.7.5. Цикл просмотра для работы с массивами. 3.7.6. Инструкции continue иЪгеак. 3.8. Инструкция goto (безусловный переход).. 3.9. Инструкция with. 3.10. Инструкция return.. 3.11. Обработка исключительных ситуаций... 3.12. Инструкция m ixin....... 3.13. Инструкция scope. 3.14.HHCTpyK4HHsynchronized.. 3.15. Конструкция a sm.... 3.16. Итоги и справочник.... 4. М ассивы, ассоциати вны е массивы и строки. 4.1. Динамические массивы.. 4.1.1.Д л ин а... 4.1.2.П роверкаграни ц.

4.1.3. Срезы.. Оглавление 4.1.4. Копирование.. 4.1.5.Проверканаравенство... 4.1.6. Конкатенация... 4.1.7. Поэлементные операции.... 4.1.8. Сужение... 4.1.9. Расширение... 4.1.10. Присваивание значения свойству.length 4.2. Массивы фиксированной длины.. 4.2.1. Длина. 4.2.2. Проверка границ...... 4.2.3. Получение срезов............... 4.2.4.Копированиеинеявныепреобразования. 4.2.5. Проверка на равенство. 4.2.6. Конкатенация..... 4.2.7.Поэлементныеоперации.. 4.3. Многомерные массивы. 4.4. Ассоциативные массивы..... 4.4.1. Длина... 4.4.2.Ч тени еизапи сьячеек. 4.4.3. Копирование................... 4.4.4. Проверка на равенство.... 4.4.5. Удаление элементов..... 4.4.6. Перебор элементов. 4.4.7. Пользовательские типы.... 4.5. Строки. 4.5.1.Кодовыеточки... 4.5.2. Кодировки. 4.5.3. Знаковые типы. 4.5.4. Массивы знаков + бонусы = строки. 4.6. Опасный собрат массива - указатель. 4.7. Итоги и справочник. 5. Данные и функции. Ф ункциональны й стиль 5.1. Написание и модульное тестирование простой функции 5.2. Соглашения о передаче аргументов и классы памяти 5.2.1. Параметры и возвращаемые значения, переданные по ссылке (с ключевым словом r e f)............... 5.2.2. Входные параметры (с ключевым словом in) 5.2.3. Выходные параметры (с ключевым словом out).. 5.2.4. Ленивые аргументы (с ключевым словом lazy). 5.2.5. Статические данные (с ключевым словом static) 5.3. Параметры типов........ 5.4. Ограничения сигнатуры... 5.5. Перегрузка.... 5.5.1. Отношение частичного порядка на множестве функций. 5.5.2. Кроссмодульная перегрузка.... 5.6. Функции высокого порядка. Функциональные литералы.. 8 Оглавление 5.6.1. Функциональные литералы против литералов делегатов.. 5.7. Вложенные функции.. 5.8. Замыкания... 5.8.1. Так, это работает... Стоп, не должно...

Нет, все ж е работает!. 5.9. Не только массивы. Диапазоны. Псевдочлены. 5.9.1. Псевдочлены и атрибут @property. 5.9.2. Свести - но не к абсурду.... 5.10. Функции с переменным числом аргументов. 5.10.1. Гомогенныефункции с переменным числом аргументов.. 5.10.2. Гетерогенные функции с переменным числом аргументов.. 5.10.3. Гетерогенные функции с переменным числом аргументов. Альтернативный подход.. 5.11. Атрибуты функций..... 5.11.1.Ч исты ефункции. 5.11.2. Атрибут nothrow... 5.12.Вы числениявовремякомпиляции.. 6. Классы. О бъектно-ори енти рованн ы й с т и л ь.. 6.1.К лассы..... 6.2. Имена объектов - это ссылки.... 6.3. Ж изненный цикл объекта. 6.3.1.Конструкторы. 6.3.2. Делегирование конструкторов. 6.3.3. Алгоритм построения объекта. 6.3.4. Уничтожение объекта и освобождение памяти... 6.3.5. Алгоритм уничтожения объекта... 6.3.6.Стратегияосвобож денияпамяти. 6.3.7. Статические конструкторы и деструктор 6.4. Методы и наследование................ 6.4.1. Терминологический «шведский стол». 6.4.2. Наследование - это порождение подтипа.

Статический и динамический ти п ы............ 6.4.3. Переопределение - только по желанию.... 6.4.4. Вызов переопределенных методов. 6.4.5. Ковариантные возвращаемые ти пы.... 6.5. Инкапсуляция на уровне классов с помощью статических членов................ 6.6. Сдерживание расширяемости с помощью финальных методов.......................... 6.6.1.Ф инальны еклассы.. 6.7. Инкапсуляция....... 6.7.1.private. 6.7.2.package......... Оглавление 6.7.3. protected... 6.7.4. public......... 6.7.5.export.. 6.7.6.Сколькоинкапсуляции?.. 6.8.0сновабезраздельнойвласти...... 6.8.1.strin g to S trin g ()..... 6.8.2. size_t toHash()... 6.8.3. bool opEquals(Object rhs).. 6.8.4.intopCm p(O bjectrhs).. 6.8.5. static Object factory (string className). 6.9.Интерфейсы. 6.9.1. Идея невиртуальных интерфейсов (NVI).. 6.9.2. Защищенные примитивы. 6.9.3. Избирательная реализация.... 6.10. Абстрактные классы 6.11. Вложенные классы.. 6.11.1.Влож енны еклассы вф ункциях. 6.11.2. Статические вложенные классы.. б.П.З.Анонимны еклассы. 6.12.Множественноенаследование. 6.13.М ножественноепорождениеподтипов. 6.13.1. Переопределение методов в сценариях множественного порождения подтипов... 6.14. Параметризированные классы и интерф 6.14.1.И сновагетерогеннаятрансляция.. 6.15.П ереопределениеаллокаторовидеаллокаторов... бЛ б.О бъекты всоре................... 6.17.Итоги. 7. Другие пользовательские типы. 7.1.Структуры. 7.1.1.Семантикакопирования.. 7.1.2. Передача объекта-структуры в функци 7.1.3. Жизненный цикл объекта-структуры. 7.1.4. Статические конструкторы и деструкторы.. 7.1.5. Методы...... 7.1.6.Статическиевнутренниеэлементы.. 7.1.7.Спецификаторыдоступа.. 7.1.8. Вложенность структур и классов. 7.1.9. Структуры, вложенные в функции.. 7.1.10. Порождение подтипов в случае структур.

Атрибут @disable.. 7.1.11. Взаимное расположение полей. Выравнивание. 7.2. Объединение..... 7.3.Перечисляемыезначения. 7.3.1. Перечисляемые типы. 7.3.2. Свойства перечисляемых типов. 10 Оглавление 7.4.a lia s.. 7.5. Параметризированные контексты (конструкция template). 7.5.1. Одноименные шаблоны.. 7.5.2.Параметрш аблонаШ 1з.. 7.6. Инъекции кода с помощью конструкции m ixin template. 7.6.1. Поиск идентификаторов внутри mixin.. 7.7.Итоги.. 8. К валиф икаторы типа.. 8.1. Квалификатор immutable. 8.1.1. Транзитивность...... 8.2. Составление типов с помощью immutable. 8.3.Н еизменяемы епараметры иметоды.. 8.4.Неизменяемыеконструкторы. 8.5. Преобразования с участием immutable.. 8.6. Квалификатор const. 8.7. Взаимодействие между const и immutable. 8.8. Распространение квалификатора с параметра на результат.. 8.9. Итоги... 9,О б р аб о т к ао ш и б о к. 9.1. Порождение и обработка исключительных ситуаций. 9.2. Типы........ 3.3.Б л ок и й п аН у.. 9.4. Функции, не порождающие исключения (nothrow), и особая природа класса Throwable. 9.5. Вторичные исключения... 9.6. Раскрутка стека и код, защищенный от исключений. 9.7. Неперехваченные исключения.. 10. К онтрактное про гр ам м и р о ван и е. 10.1. Контракты...... 10.2.Утверждения.. Ю.З.Предусловия. 10.4.Постусловия. Ю.б.Инварианты. 10.6. Пропуск проверок контрактов. Итоговые сборки.. 10.6.1. enforce —это не (совсем) a sse r t.. 10.6.2. assert(false) - останов программы. 10.7. Контракты - не для очистки входных данных. 10.8. Наследование.... 10.8.1. Наследование и предусловия.... 10.8.2.Н аследованиеипостусловия.... 10.8.3. Наследование и инварианты. 10.9. Контракты и интерфейсы..... Оглавление И.Р асш и рен и ем асш таба. 11.1.П акеты имодули.... ll.l.l.O б ъ я в л eн и я iш p o rt. 11.1.2. Базовые пути поиска модулей. 11.1.3.Поискимен. 11.1.4. Объявления public import.. 11.1.5. Объявления static import. 11.1.6.Избирательныевключения. 11.1.7. Включения с переименованием. 11.1.8. Объявление модуля.... 11.1.9.Резюмемодулей................... 11.

2. Безопасность.. 11.2.1. Определенное и неопределенное поведение.. 11.3.2. Атрибуты @ safe, @ tru sted и @ sy ste m.. 11.3. Конструкторы и деструкторы модулей.... 11.3.1. Порядок выполнения в рамках модуля. 11.3.2. Порядок выполнения при участии нескольких модулей... 11.4.Документирующиекомментарии. 11.5. Взаимодействие с С и С + +.. 11.5.1. Взаимодействие с классами С + +.. 11.6.K nK 4eB0e^0B0deprecated. 11.7. Объявления версий. 11.8.0тладочныеобъявления. 11.9. Стандартная библиотека D.. 11.10. Встроенный ассемблер.. 11.10.1. Архитектура x86....................... 11.10.2. Архитектура x86-64. 11.10.3. Разделение на версии. 11.10.4.Соглашенияовызовах. 11.10.5.Рациональность.. 12.П ерегрузкаоператоров.. 12.1. Перегрузка операторов в D..... 12.2. Перегрузка унарных операторов.. 12.2.1. Объединение определений операторов с помощью выраженияпйхш.. 12.2.2. Постфиксный вариант операторов увеличения и уменьшения на единицу..... 1 2.2.3.n ep erp y3K aon ep aT op acast.. 12.2.4. Перегрузка тернарной условнойоперации и вет 12.3.Перегрузкабинарныхоператоров. 12.3.1. Перегрузка операторов в квадрате... 12.3.2.Коммутативность. 12.4.Перегрузкаоператоровсравнения.. 12.5.Перегрузкаоператоровприсваивания.... 12 Оглавление 12.6.Перегрузкаоператоровиндексации..... 12.7. Перегрузка операторов среза. 1 2.8.0 п ер а т о р $............... 1 2.9.I I e p e r p y 3 K a f o r e a c h.. 12.9.1. foreach с примитивами перебора.. 12.9.2. foreach с внутренним перебором.. 12.10. Определение перегруженных операторов в классах.. 12.11. Кое-что из другой оперы: opDispatch. 12.11.1. Динамическое диспетчирование с opDispatch. 12.12.И тогиисправочник.. 1 3.П ар ал л ел ьн ы ев ы ч и сл ен и я.. 13.1. Революция в области параллельных вычислений. 13.2. Краткая история механизмов разделения данных.. 13.3. Смотри, мам, никакого разделения (по умолчанию)..... 13.4.3апускаем поток.. 13.4.1.Неизменяемоеразделение. 13.5. Обмен сообщениями между потоками. 13.6. Сопоставление по шаблону с помощью receive..... 13.6.1.П ервоесовпадение..... 13.6.2. Соответствие любому сообщению.. 13.7. Копирование файлов - с выкрутасом... 13.8. Останов потока.. 13.9.П ередачанеш татныхсообщ ений.. 13.10. Переполнение почтового ящика.. !З.Н.К валиф икатортипавЬ агед.... 13.11.1. Сюжет усложняется:

квалификатор shared транзитивен.. 13.12. Операции с разделяемыми данными и их применение 13.12.1. Последовательная целостность разделяемых данных.. 13.13. Синхронизация на основе блокировок через синхронизированные классы. 13.14. Типизация полей в синхронизированных классах.... 13.14.1. Временная защита == нет утечкам.. 13.14.2. Локальная защита = = разделение хвостов... 13.14.3.Принудительныеидентичныемьютексы.... 13.14.4. Фильм ужасов: приведение от 13.15. Взаимоблокировки и инструкция synchronized.. 13.16. Кодирование без блокировок с помощью разделяемых классов... 13.16.1.Разделяемы екласс ы..... 13.16.2.П араструктурбезблокировок. 13.17. Статические конструкторы и потоки.. 13.18. Итоги.. Литература.... А лф авитны й у к а з а т е л ь.. 06 авторе Андрей Александреску - автор неофициального термина «современ­ ный С++». Сегодня под этим понимают множ ество полезны х стилей и идей программирования на С++. Книга А лександреску «Современное проектирование на С++: обобщ енное программирование и прикладны е шаблоны проектирования» (Вильямс, 2004) полностью изм енила мето­ дику программирования на С ++ и оказала огромное влияние не только на непосредственную работу на С++, но и на другие язы ки и системы.

В соавторстве с Гербом Саттером А ндрей написал «Стандарты програм­ мирования на С++: 101 правило и рекомендация» (Вильямс, 2005).

Благодаря разработанным им многочисленным библиотекам и прило­ жениям, а такж е исследовательской работе в области маш инного обуче­ ния и обработки естественных языков, А ндрей снискал уваж ение как практиков, так и теоретиков.

С 2006 года он стал правой рукой Уолтера Брайта - автора язы ка про­ граммирования D и первого, кто взялся за его реализацию. И менно Андрей А лександреску предлож ил многие важные средства D и создал большую часть стандартной библиотеки D. Все это позволило ем у напи­ сать эту авторитетную книгу о новом языке. Ваш ингтонский универси­ тет присудил Андрею степень доктора философии компьютерных наук, а университет «Политехника» в Б ухаресте - степень бакалавра элект­ ротехники. Он такж е является научным сотрудником Facebook.

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

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

Не будучи сам ученым, я понимаю, что движ ет такими людьми. Мне, инженеру, тож е знакома радость творения, создания чего-то из ничего.

Одна из моих любимых книг - «Братья Райт как инженеры» Уольда1.

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

Мои ранние увлечения, суть которых отражают слова с первых страниц «Руководствадля любителей фейерверков» Бринли2 - «восхищение и за чарованность всем, что горит и взрывается», —позж е выросли в желание создавать то, что работает быстрее и лучше.

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

Вот я и начал создавать воображаемые миры на компьютере. Первым стала игра Empire: W argam e of the Century3. Компьютеры тогда были недостаточно мощны, чтобы можно было нормально играть в нее, и я за­ интересовался оптим изацией программ. Это привело к изучению ком­ пиляторов, которые генерируют код, и, естественно, к высокомерному 1 Quentin R. Wald «The Wright Brothers as Engineers: an Appraisal and Flying with the Wright Brothers, one Man’s Experience», 1999.

2 Bertrand R. Brinley «Rocket Manual for Amateurs*, Ballantine, 1968.

3 Одна из первых графических компьютерных стратегических игр, оказав­ шая большое влияние на дальнейшее развитие игр этого жанра, в частно­ сти Civilisation. См. http://www.classicempire.com/. - Прим. пер.

Предисловие Уолтера Брайта «я могу написать компилятор получш е этого». Влюбившись в язы к С, я захотел создать компилятор и для него. И за пару лет, работая непол­ ный день, без труда справился с этим. Затем мое внимание привлек язык Бьёрна Страуструпа С++, и я реш ил, что смогу дополнить компилятор С соответствующими возмож ностями за пару месяцев (!).

Спустя десять лет я все ещ е работал над этим. В процессе реализации я изучил язык во всех тонкостях. Д ля поддерж ки обш ирной пользова­ тельской базы необходимо было хорош о понимать, как воспринимают язык другие люди, и знать, что работает, а что нет. Я не могу пользо­ ваться чем-то и не думать, как м ож но это улучш ить. В 1999 году я ре­ шил воплотить свои идеи. Началось с язы ка программирования M ars.

Однако мои коллеги стали называть его D - сначала в ш утку, но потом имя прижилось. Так и появился на свет язы к программирования D.

К моменту написания этого текста язы ку D исполнилось у ж е десять лет и у него появилось новое, более значительное воплощение, которое ино­ гда называют D2. Вместо единственного человека, не отрывающ егося от клавиатуры, над языком D теперь трудится целое всемирное сообщ ест­ во разработчиков, которые заним аю тся всеми аспектами языка и под­ держивают экосистему библиотек и инструментов.

Сам язык (которому посвящ ена эта книга) эволюционировал от скром­ ных основ до очень мощного язы ка, виртуозно реш аю щ его задачи про­ граммирования разными способами. Насколько мне известно, в D остро­ умно и оригинально сочетаются несколько парадигм программирова­ ния: императивное, объектно-ориентированное, ф ункциональное и ме­ тапрограммирование.

Первое, что приходит в голову после подобного заявления: такой язы к не может быть простым. И в самом деле, D - непростой язык. Но, д у­ маю, не стоит судить о язы ке по его слож ности. Гораздо полезнее задать­ ся вопросом о том, как выглядят программные решения на этом язы ке.

Просты ли, изящны ли программы на D - или сложны и бестолковы?

Один мой коллега с богатым производственным опытом зам етил, что IDE1 - необходимый для программирования инструмент, потому что по­ зволяет одним щелчком мыши сгенерировать сотни строк стандартного кода. При использовании язы ка D нет острой потребности в ГОЕ, по­ скольку, вместо того чтобы полагаться на фокусы генерации «загото­ вок» разного рода «помощниками», D исключает сам у идею стандарт­ ных заготовок, применяя интроспекцию и собственные возмож ности генерации кода. Программист у ж е не увидит стандартный код. О при­ сущей программам слож ности заботится язы к, а не IDE.

Предположим, кто-то хочет написать программу в стиле объектно-ори­ ентированного программирования (ООП) на простом язы ке без встро­ енной поддержки этой парадигмы. Он м ож ет сделать это ценой у ж а с­ 1 IDE (Integrated Development Environment) - интегрированная среда разра­ ботки.- Прим. пер.

16 Предисловие Уолтера Брайта ных и почти всегда напрасны х усилий. Но если более сложны й язык у ж е поддерживает ООП, писать ООП-программы легко и изящ но. Язык слож нее, а код пользователя - проще. Вот куда стоит двигаться.

Чтобы легко и изящ но писать код, реализую щ ий широкий спектр за­ дач, необходим язы к с поддерж кой нескольких разных парадигм про­ граммирования. Грамотно написанный код должен красиво смотреть­ ся, и, как ни странно, красивый код - это зачастую правильный код. Не знаю, чем обусловлена эта взаимосвязь, но обычно так и есть. Это как с самолетами: тот, что хорошо выглядит, как правило, и летает хорошо.

То есть средства язы ка, позволяющие выражать алгоритмы красиво, скорее всего, хорош ие средства.

Однако только простоты и изящ ества написания кода мало для того, чтобы назвать язы к программирования хорошим. Сегодня программы быстро растут в объеме, и конда этому не видно. С такими объемами для обеспечения корректности программ все менее целесообразно пола­ гаться на знания и опыт программиста и традиционные способы про­ верки работоспособности кода. Все более стоящ им каж ется подход, ко­ гда выявление ош ибок гарантирует маш ина. Здесь D мож ет похвастать­ ся множеством стратегий, применяя которые, программист получит такие гарантии. Эти средства включают контракты, безопасность памя­ ти, различные атрибуты ф ункций, свойство неизменности, защ иту от «угона имен» (hijack)1, ограничители области видимости, чистые функ­ ции, юнит-тесты и изоляцию данны х при многопоточном программи­ ровании.

Нет, мы не забыли о производительности! Несмотря на многочисленные высказывания о том, что вопрос быстродействия больше не актуален, и на то, что компьютеры работают в тысячу раз быстрее, чем когда я пи­ сал свой первый компилятор, потребность в более быстрых программах, очевидно, не снизится никогда. D - это язык для системного програм­ мирования. Что это значит? В двух словах, это значит, что на D можно писать операционную систему, равно как и код приложений и драйве­ ров устройств. С более технической точки зрения это значит, что про­ граммы на D имеют доступ ко всем возможностям машины. То есть м ож но использовать указатели, совмещать указатели и выполнять над ними арифметические операции, обходить систему типизации и даж е писать код прямо на ассемблере. Нет ничего, что программисту на D бы­ ло бы полностью недоступно. Например, реализация сборщика мусора для самого язы ка D написана полностью на D.

1 Суть проблемы следующая: программист обращается к какому-то символу (функции, классу и т..) по имени, но вследствие перегрузки функций по ти­ пам аргументов (из-за переопределения методов в дочерних классах) возни­ кает спорная ситуация, и компилятор неявно обращается к некоторому символу - возможно, не тому, который нужен программисту. Компилятор D в неоднозначных ситуациях генерирует ошибку. См. http:// dlang.org/hijack.

html. - Прим. науч.ред.

Предисловие Уолтера Брайта Минуточку. Разве такое возможно? Каким образом язы к м ож ет одно­ временно предоставлять и немыслимые гарантии безопасности, и не­ подвластные никакому контролю операции с указателями? Ответ в том, что гарантии этого типа основаны на используемы х конструкциях язы ­ ка. Например, с помощью атрибутов ф ункций и конструкторов типов можно предотвратить ош ибки в реж им е компиляции. Контракты и ин­ варианты предоставляют гарантии корректности работы программы во время исполнения.

Большинство качеств D в той или иной форме когда-то у ж е появлялись в других язы ках. Взяты е по отдельности, они не оправдывают появле­ ние нового языка. Но их ком бинация - это больше, чем просто сум м а частей. И комбинация D позволяет ем у претендовать на звание привле­ кательного языка с изящ ны ми и эффективными средствами дл я реш е­ ния необычайно широкого круга задач программирования.

Андрей Александреску известен оригинальными идеями, сформиро­ вавшими основное направление программистской мысли (см. его нова­ торскую книгу «Современное проектирование на С++»). А ндрей примк­ нул к команде разработчиков язы ка D в 2006 году. Его вклад - серьез­ ная теоретическая база по программированию, а такж е неиссякаемый поток инновационных решений проблем программного проектирова­ ния. D2 сформировался в основном благодаря ему, а эта книга во многом развивалась совместно с D. Одно из замечательных свойств написанного им о D в том, что это сочинение - не простое перечисление фактов. Это ответы на вопросы, почему были выбраны те или иные проектные ре­ шения. Зная, по каким причинам язы к стал именно таким, гораздо лег­ че и быстрее понять его и начать программировать на нем.

В кпиге Андрей иллюстрирует эти причины, решая с помощью D мно­ жество фундаментальных задач программирования. Этим он показы­ вает не только как работает D, но и почему он работает, и как его ис­ пользовать.

Надеюсь, вы получите столько ж е удовольствия от программирования на D, сколько я получил от работы над ним. Страницы книги А н дрея просто излучают восхищ ение языком. Д умаю, вам понравится!

Уолтер Брайт Январь 2010 г.

Предисловие Скотта Мейерса Как ни крути, С ++ невероятно успешен. Но д а ж е самые страстные по­ клонники язы ка не будут отрицать, что управлять этим зверем непро­ сто. Сложность С ++ повлияла на структуру самых популярных его пре­ емников —Java и C #. Оба стремились избежать сложности своего пред­ ш ественника, предоставив его основные возможности в более удобной для использования форме.

Снижение слож ности велось по двум главным направлениям. Одно из них - отказ от «сложных» средств языка. Например, управление памя­ тью вручную (единственный способ, доступный пользователям С++) было заменено «сбором мусора». Считалось, что выгоды от применения шаблонов никогда не оправдают соответствующ их затрат. Поэтому ран­ ние версии Java и C # не включали ничего похож его на поддержку обоб­ щенного программирования в С++.

Второе направление сниж ения сложности подразумевало замену «сложных» средств С ++ сходными, но более простыми для понимания конструкциями. М ножественное наследование С++ превратилось в про­ стое наследование плюс интерфейсы. Современные версии Java и C# поддерживаю т шаблоноподобные обобщенные классы, которые проще шаблонов С++.

Эти языки-потомки претендовали на нечто большее, чем просто менее слож но делать то ж е, что и С++. Оба определяли виртуальные машины, добавляли поддерж ку рефлексии и предоставляли обширные библио­ теки, позволяю щ ие многим программистам сосредоточиться не на на­ писании нового кода, а на «склеивании» у ж е имеющ ихся компонентов.

Результат - С-подобные язы ки для продуктивного программирования.

Если требуется быстро создать программный продукт, более или менее соответствующ ий комбинации готовых элементов - а большинство про­ граммного обеспечения попадает в эту категорию, - Java и C # будут лучш им выбором по сравнению с С++.

Но С++ и не предназначен для скоростной разработки - это язык для сис­ т емного программирования. Он создавался как альтернатива С по воз­ можностям «общения» с аппаратным обеспечением (таким как драйверы и встроенные системы), напрямую использующая библиотеки и струк­ туры данны х С (например в унаследованных системах) и работающая на пределе производительности аппаратного обеспечения. На самом де­ Предисловие Скотта Мейерса ле, нет ничего парадоксального в том, что узк ие места виртуальны х машин Java и C # написаны на С++. Реализация высокопроизводитель­ ных виртуальных маш ин - задача языка для сист емного программи­ рования, а не прикладного.

Цель D - стать наследником С ++ в области системного программирова­ ния. Как и Java с C #, D стремится избеж ать слож ности С++, поэтому он отчасти задействует те ж е техники. Сборке мусора - «добро пож ало­ вать», ручному управлению памятью - «до свиданья»1. Простому насле­ дованию и интерфейсам - да, множественному наследованию - нет. Вот и все сходство, дальш е D идет у ж е собственной дорогой.

Она начинается с выявления функциональны х изъянов С++ и их вос­ полнения. Текущая версия С ++ не поддерживает Ю никод, его новая версия (C++11), находящ аяся в стадии разработки, так ж е предоставля­ ет очень ограниченную поддерж ку этой кодировки. D поддерживает Юникод с момента своего появления. Как современный С++, так и C++Ox не предоставляют ни средства для работы с модулями (в том числе для их тестирования), ни инструментарий для реализации парадигмы кон­ трактного программирования, ни «безопасные» подмнож ества (где не­ возможны ошибки при работе с памятью). D предлагает все вышепере­ численное, не ж ертвуя при этом способностью генерировать высокока­ чественный маш инный код.

Там, где С++ одновременно и мощный, и слож ны й, D пы тается быть не менее мощным, но более простым. Лю бители шаблонного метапрограм­ мирования на С++ продемонстрировали, насколько важ на технология вычислений на этапе компиляции, но, для того чтобы использовать их, им пришлось прыгать через горящ ие обручи синтаксиса. D предлагает те ж е возможности, избавляя от лингвистических мучений. В С ++ вы знаете, как написать функцию, но при этом не имеете ни малейш его понятия о том, как написать соответствующ ую функцию, вычисляе­ мую на этапе компиляции. А в язы ке D, зная, как написать функцию, вы у ж е точно знаете, как написать ее вариант времени ком пиляции, поскольку код тот ж е самый.

Один из самых интересных моментов, где D расходится со своими co братьями-наследниками С++, - подход к параллельным вычислениям при многопоточном программировании. Ввиду того что неверно си нхро­ низированный доступ к разделяемым данным («гонки за данными») это западня, угодить в которую легко, а выбраться слож но, D перевора­ чивает традиционные представления с ног на голову: по умолчанию данные не разделяются м еж ду потоками. По мнению разработчиков D, благодаря глубоким иерархиям кэшей в современном аппаратном обес­ печении память все равно зачастую реально не разделяется м еж ду ядра­ 1 На самом деле, тут все зависит от желания. Как и подобает языку для сис­ темного программирования, D позволяет вручную управлять памятью, ес­ ли вы действительно этого хотите.

20 Предисловие Скотта Мейерса ми и процессорами, так зачем по умолчанию предлагать разработчикам абстракцию, которая не просто фиктивна, но еще и чревата ошибками, с трудом поддаю щ имися отладке?

Все это (и не только) превращает D в достойный внимания экземпляр среди наследников С и является веским доводом к прочтению этой кни­ ги. Тот факт, что ее автор - А ндрей Александреску, только усиливает доводы «за». Как один из проектировщиков D, реализовавший значи­ тельную часть его библиотеки, Андрей знает D лучш е кого бы то ни бы­ ло. И, конечно, он м ож ет описать этот язык программирования, а кроме того, ещ е и объяснить, почему D стал именно таким. Актуальные сред­ ства язы ка были включены в него намеренно, а те, которых пока нет, отсутствуют тож е не без причины. Андрей - один из немногих, кто спо­ собен осветить все эти вопросы.

И освещает он их на редкость увлекательно. Посреди ненужного, каза­ лось бы, «лирического отступления* (которое на самом деле является станцией на пути к тому пункту назначения, куда вас хотят доставить) Андрей успокаивает: «Догадываюсь, что сейчас вы задаетесь вопросом, имеет ли все это отношение к вычислениям во время компиляции. От­ вет: имеет. Прошу немного терпения». Понимая, что диагностические сообщения сборщика далеко не интуитивно понятны, Андрей замечает:

«Если вы забыли написать --main, не волнуйтесь: компоновщик тут ж е витиевато напомнит вам об этом на своем родном языке —зашифрован­ ном клингонском1». Д аж е ссылки на другие источники у Александре­ ску выглядят по-особому. Вам не просто дают номер, под которым рабо­ та Уодлера «Доказательства —это программы» числится в списке лите­ ратуры, а предлагают «прочесть увлекательную монографию „Доказа­ тельства - это программы" Уодлера». Классический труд Фридла «Регу­ лярные выражения»2 не просто рекомендуется к прочтению, а «горячо рекомендуется ».

И разум еется, в этой книге о язы ке программирования много примеров исходного кода, судя по которым А ндрей - отнюдь не заурядный автор.

Вот определенный им прототип для функции поиска3:

bool find(int[] haystack, int needle);

Это книга знающ его автора об интересном языке программирования.

Уверен, вы не пож алеете, что прочли ее.

Скотт Мейерс Январь 2010 г.

1 Клингонский язык - искусственный язык, специально придуманный для клингонов (расы воинов) - персонажей кинофильмов, сериалов, книг и ком­ пьютерных игр о вымышленной вселенной «Звездный путь». Существую­ щие естественные языки он напоминает весьма слабо. - Прим. пер.

2 Ф ридл «Регулярные выражения», 3-е издание, Символ-Плюс, 2008.

3 Если перевести идентификаторы, код примет вид: bool найти(1г^[ ] стог сена, int иголка);

. - Прим. пер.

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

Автор книги хотел отразить язы к таким, каким он «должен быть*. Н е­ которые аспекты языка на момент написания книги ещ е не были реали­ зованы в компиляторах, другие возмож ности, предоставляемые компи­ ляторами, напротив, не попали в книгу. Автор справедливо полагал, что читатель, ж елаю щ ий ознакомиться с возмож ностями конкретной реализации компилятора, мож ет обратиться к документации (напри­ мер, документация для эталонного компилятора dmd размещ ена на сай­ те d-program m ing-language.org). К сож алению, на момент выхода книги эта документация ещ е не была переведена на русский язык.

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

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

Следует пояснить перевод некоторых терминов.

Первый неоднозначный момент - перевод слова «character». В подавля­ ющем большинстве издаваемы х сейчас книг это слово переводится как «символ». М ежду тем данный перевод не вполне корректен. Со времен книги Гриса1о конструировании компиляторов в русском язы ке симво­ лом считается синтаксическая единица (symbol). Например, double, main 1 Грис Д. «Конструирование компиляторов для цифровых вычислительных машин». - М.: Мир, 1975.

22 Предисловие научных редакторов перевода и оператор ++ —это символы. В учебнике информатики Бауэра и Гооза символ определен как знак (литера, буква алфавита) со смыслом. Назы­ вать символом литеру - некорректно. Мы использовали слово «символ* в значении «symbol*, или «знак со смыслом» (например, символ перево­ да строки). Термин ж е «character» мы перевели как «знак». Наблюдает­ ся так ж е некоторый конфликт термина «знак» в смысле «буква», или «литера», и термина «знак» (sign) в математическом смысле (+ или -).

Но, как правило, из контекста понятно, в каком смысле употребляется слово «знак». Например, тип char мы называем знаковым, или литер­ ным типом, имея в виду, что в переменной этого типа может храниться знак алфавита, а не число со знаком. К слову сказать, в D тип char пред­ назначен только для хранения знака (или части знака) в кодировке UTF-8 (и, являясь интегральным типом, в математическом смысле он всегда беззнаковы й, как unsigned char в С). Д ля представления ж е одно­ байтного целого числа D вводит два дополнительных типа - byte (со знаком) и ubyte (без знака). То есть под «знаковым типом» мы понимаем char, wchar или dchar, а тип i n t называем целым типом, или целым типом со знаком.

Второй аспект - перевод слова «statem ent». Во многих книгах такие ве­ щи, как if, switch, while, называют операторами. В книге про D такой перевод неуместен, так как язы к предоставляет возможность перегруз­ ки операторов (operator overloading) +, *, % так далее для пользователь­ и ских типов, и неизбеж на путаница с этими операторами. Поэтому мы переводим «statem ent* как «инструкция».

Напоследок несколько слов о самой книге. Эту книгу стоит прочитать всем. Если вы у ж е знакомы с D, эта книга поможет лучш е понять, поче­ му этот язы к устроен именно так, и научиться использовать его с наи­ большей отдачей. Если вы хотите узнать новый для себя язык, эта кни­ га - то, что вам нуж но. Поверьте, изучение D стоит потраченного време­ ни, и хотя этот язы к ещ е молод и находится в процессе развития, уж е сейчас его мож но использовать для решения серьезных задач. Причем это реш ение будет одновременно элегантным и эффективным.

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

Игорь Степанов и Владимир Пантелеев 1 Бауэр Ф. JI., Гооз Г. «Информатика. Вводный курс: в 2-х ч.» - Пер. с нем. M.: Мир, 1990.

Введение Обретая силу в простоте, язы к программирования порож дает красоту.

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

D - это язык, который последовательно старается правильно действо­ вать в пределах выбранных им ограничений, таких как доступ систем­ ного уровня к вычислительным ресурсам, высокая производительность и синтаксическая простота, к которой стремятся все произош едш ие от С языки. Стараясь правильно действовать, D порой поступает традицион­ но - как другие языки, а порой ломает традиции с помощью свежего, инновационного решения. Иногда это приводило к пересмотру принци­ пов, которым, казалось, D никогда не изменит. Например, большие фрагменты программного кода, а то и целые программы, могут быть на­ писаны с помощью хорошо определенного, не допускающего ошибок па­ мяти «безопасного подмножества» D. Ценой небольшого ограничения доступа на системном уровне приобретается огромное преимущ ество при отладке программ.

D заинтересует вас, если для вас важны следую щ ие аспекты:

• П роизводит ельность. D - это язы к для системного программирова­ ния. Его модель памяти, несмотря на сильную типизацию, совмес­ тима с моделью памяти С. Ф ункции на D могут вызывать ф ункции на С, а функции на С могут использовать ф ункции D без каких-либо промежуточных преобразований.

• Выразит ельност ь. D нельзя назвать небольшим, минималистич ным языком, но его удельная мощность достаточно велика. Он по­ зволяет определять наглядные, не требую щ ие объяснений инструк­ ции, точно моделирующ ие слож ны е реалии.

• «Крутящий момент». Любой лихач-«самоделкин» ск аж ет вам, что мощность еще не все - было бы где ее применить. На одних язы ках лучш е всего пиш утся маленькие программы. Синтаксические и з­ лишества других оправдываются только начиная с определенного объема программ. D одинаково эффективно помогает справляться 24 Введение и с короткими сценариями, и с большими программами, и для него отнюдь не редкость целый проект, органично вырастающий из про­ стенького скрипта в единственном файле.

• П араллельн ы е вы числения. П одход к параллельным вычислениям несомненное отличие D от похож их языков, отраж аю щ ее разрыв ме­ ж д у современными аппаратными решениями и архитектурой ком­ пьютеров прошлого. D покончил с проклятьем неявного разделения памяти (хотя и допускает статически проверенное, явно заданное разделение) и поощ ряет независимые потоки, которые «общаются»

друг с другом посредством сообщ ений.

• Обобщенное программирование. Идея обобщенного кода, манипули­ рующего другим кодом, была впервые реализована в мощных макро­ сах Лиспа, затем в шаблонах С++, обобщенных классах Java и схожих конструкциях др уги х языков. D такж е предлагает невероятно мощ­ ные механизмы обобщ енного и порождающ его программирования.

• Э клект и зм. D подразумевает, что к аж дая парадигма программиро­ вания ориентирована на свою задачу разработки. Поэтому он пред­ полагает высокоинтегрированный объединенный стиль программи­ рования, а не Единственно Верный Подход.

• «Это мои принципы. А если они вам не нравят ся, то у меня есть и другие1. D старается всегда следовать своим принципам устройства язы ка. Иногда они идут вразрез с соображениями сложности реали­ зации и трудностей использования и, главное, с человеческой приро­ дой, которая не всегда находит скрытую логику здравой и интуитив­ но понятной. В таких случаях все языки полагаются на собственное бесконечно субъективное понимание баланса, гибкости и - особен­ но - хорошего вкуса. На мой взгляд, D как минимум неплохо смот­ рится на фоне других языков, разработчикам которых приходилось принимать реш ения того ж е плана.

Кому адресована эта книга Предполагается, что вы программист. То есть знаете, как решить типич­ ную задачу программирования с помощью языка, на котором вы пише­ те. Н еважно, какой конкретно это язык. Если вы знаете один из языков, произош едш их от А лгола (С, С++, Java или C #), то будете иметь некото­ рое преимущ ество перед другими читателями - синтаксис сразу пока­ ж ется знакомым, а риск встретить «мнимых друзей» (одинаковый син­ таксис с разной семантикой) будет минимальным. (Особенно это касает­ ся случаев, когда вы вставляете кусок кода на С в D -файл. Он либо ском пилируется и будет делать то ж е самое, либо не скомпилируется вообще.) Книга, знаком ящ ая с языком, была бы скучной и неполной, если бы не объясняла, зачем в язы к включены те или иные средства, и не показы­ 1 Афоризм американского комика Граучо Маркса. - Прим. ред.

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

Структура книги Глава 1 - это бодрящ ая прогулка с целью знакомства с основами язы ка.

На этом этапе не все детали полностью видны, но вы см ож ете почувст­ вовать язык и научиться писать на нем простейш ие программы. Главы 2 и 3 - необходимое перечисление вы ражений и инструкций язы ка со­ ответственно. Я попытался скрасить неизбеж ную монотонность по­ дробного описания, подчеркнув детали, отличающ ие D от др уги х тра­ диционных языков. Надеюсь, вам будет легко читать эти главы подряд, а такж е возвращаться к ним за справкой. Таблицы в конце этих глав — это «шпаргалки», интуитивно понятные краткие справочники.

В главе 4 описаны встроенные типы: массивы, ассоциативные массивы и строки. Массив можно представить себе как указатель с аварийным выключателем. Массивы в D - это средство, обеспечивающ ее безопас­ ность памяти и позволяющее вам наслаж даться языком. Строки - это массивы знаков Ю никода в кодировке UTF. П овсеместная поддерж ка Юникода в языке и стандартной библиотеке позволяет корректно и эф ­ фективно обрабатывать строки.

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

П оследующие главы знакомят с абстракциями-блоками. Глава 5 объ­ единяет описание различны х видов функций: параметризированны х функций реж им а компиляции (шаблоны функций) и ф ункций, вычис­ ляемых во время компиляции. Обычно такие вопросы рассматривают­ ся в более *продвинутых» главах, но в D работать с этими средствами достаточно просто, так что раннее знакомство с ними оправданно.

В главе 6 обсуж дается объектно-ориентированное программирование на основе классов. Как и раньше, здесь органично и комплексно подается информация о параметризированных классах. Глава 7 знакомит с до­ полнительными типами, в частности с типом struct, позволяющ им, обычно совместно с классами, эффективно создавать абстракции.

26 Введение Следующие четыре главы описывают довольно специализированные, обособленные средства. Глава 8 посвящена квалификаторам типов. Ква­ лификаторы надеж но гарантируют от ошибок, что одинаково ценно как для однопоточных, так и для многопоточных приложений. В главе рассмотрены модели обработки исключительных ситуаций. В главе представлен мощный инструментарий D, реализующ ий парадигму кон­ трактного программирования. Этот материал намеренно вынесен в от­ дельную главу (а не включен в главу 9) в попытке развеять миф о том, что обработка ошибок и контрактное программирование - практически одно и то ж е. В главе 10 как раз и объясняется, почему это не так.

В главе 11 вы найдете информацию и рекомендации по построению боль­ ш и х программ из компонентов, а такж е небольшой обзор стандартной библиотеки D. В главе 12 рассмотрены вопросы перегрузки операторов, без которой серьезно пострадали бы многие абстракции, например ком­ плексные числа. Наконец, в главе 13 освещен оригинальный подход D к многопоточному программированию.

Краткая история Как бы сентиментально это ни звучало, D - дитя любви. Когда-то в 1990-х Уолтер Брайт, автор компиляторов для С и С++, решил, что больше не хо­ чет работать над ними, и задался целью определить язык, каким, по его мнению, «он должен быть». Многие из нас в тот или иной момент начина­ ют мечтать об определении Правильного Языка;

к счастью, Уолтер уже обладал значительной частью инфраструктуры: генератором кода (back end), компоновщиком, а главное —широчайшим опытом построения язы­ ковых процессоров. Благодаря этому опыту перед Уолтером открылась интересная перспектива. По какому-то таинственному закону природы плохо спроектированная функциональность языка проявляется в логи­ чески запутанной реализации компилятора, как отвратительный харак­ тер Дориана Грея проявлялся на его портрете. Проектируя свой новый язык, Уолтер планомерно старался избежать таких патологий.


Едва зарож даю щ ийся тогда язы к был схож по духу с С++, поэтому про­ граммисты называли его просто D, несмотря на первоначальную попыт­ ку Уолтера даровать ем у титул «Марса*. По причинам, которые вскоре станут очевидными, назовем этот язы к D1. Страсть и упорство, с кото­ рыми Уолтер работал над D1 несколько лет, привлекали все больше еди­ номышленников. К 2 0 0 6 году D1 достиг уровня сильного языка, техни­ чески способного на равных соперничать с такими уж е признанными язы ками, как Java и С++. Но к тому времени уж е было ясно, что D1 ни­ когда не станет популярным, поскольку, в отличие от других языков, он не обладал функциональной индивидуальностью, оправдывавшей его сущ ествование. И тогда Уолтер совершил дерзкий маневр: решив пред­ ставить D1 в качестве этакой первой сырой версии, он перевел его в ре­ ж и м поддерж ки и приступил к разработке нового проекта - второй ите­ рации язы ка, не обязанной поддерживать обратную совместимость.

Введение Пользователи текущ ей версии D1 по-преж нему выигрывали от исправ­ ления ошибок, но никаких новых возмож ностей D1 не предоставлял.

Реализовать определение наилучш его языка было суж дено язы ку D2, который я и называю просто D.

Маневр удался. Первая итерация показала, что достойно внимания, а чего следует избегать. Кроме того, мож но было не спешить с рекламой нового языка - новые члены сообщ ества могли спокойно работать со ста­ бильной, активно используемой версией D1. Поскольку процесс разра­ ботки не был ограничен ни обратной совместимостью, ни сроками, м ож ­ но было спокойно оценить альтернативы развития проекта и выработать правильное направление. Чтобы ещ е больше облегчить разработку, Уол­ тер призвал на помощь коллег, в том числе Бартоша Милевски и меня.

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

Тем временем D явно перерос свое прозвищ е «улучшенный С++», пре­ вратившись в мощный многофункциональный язы к, вполне способ­ ный оставить без работы как язы ки для системного и прикладного (промышленного) программирования, так и язы ки сценариев. Остава­ лась одна проблема: весь этот рост и все усовершенствование прош ли никем не замеченными;

подходы D к программированию были доку­ ментированы очень слабо.

Книга, которая сейчас перед вами, - попытка восполнить это уп ущ е­ ние. Надеюсь, читать ее вам будет так ж е приятно, как мне - писать.

Благодарности У языка D было столько разработчиков, что я и не пытаюсь перечис­ лить их всех. Особо выделяются участники новостной группы d i g i t a l mars.D из сети U senet. Эта группа была для нас одновременно и рупором, и полигоном для испытаний, куда мы выносили на суд свои проектные решения. Кроме того, ребята из digitalmars.D сгенерировали множ ество идей по улучшению языка.

В разработке эталонной реализации компилятора dmd1 Уолтеру помога­ ло сообщество, особенно Шон Келли (Sean Kelly) и Дон Клагстон (Don Clugston). Шон переписал и усовершенствовал стандартную библиотеку, подключаемую во время исполнения (включая «сборщик мусора»). Кро­ ме того, Келли стал автором основной части реализации библиотеки, от­ вечающей за параллельные вычисления. Он мастер своего дела, а зна­ чит, если в ваших параллельных вычислениях появляются ош ибки, то 1 Название компилятора языка D dm расшифровывается как Digital Mars D.

d Digital Mars - организация, которая занимается разработкой этого компи­ лятора. - Прим. пер.

28 Введение они, увы, скорее всего, ваши, а не его. Дон - эксперт в математике вооб­ ще и во всех аспектах дробны х вычислений в частности. Его огромный труд позволил поднять численные примитивы D на небывалую высоту.

Кроме того, Дон до предела использовал способности D по генерирова­ нию кода. К ак только код эталонной реализации был открыт для широ­ кого доступа, Дон не устоял перед соблазном добавить в него что-то свое. Вот так он и занял второе место среди разработчиков компилято­ ра dmd. И Ш он, и Дон проявляли инициативу, выдвигая предложения по усовершенствованию специф икации D на протяжении всего процес­ са разработки. П оследнее (но не по значению) их достоинство в том, что они чумовые хакеры. С ними очень приятно общаться как в жизни, так и виртуально. Не знаю, чем стал бы язык без них.

Что касается этой книги, я бы хотел сердечно поблагодарить всех рецен­ зентов за отзывчивость, с которой они взялись за эту сложную и небла­ годарную работу. Б ез них эта книга не стала бы тем, что она представля­ ет собой сейчас (так что если она вам не нравится, пусть вас утешит то, что она могла быть гораздо хуж е). Поэтому позвольте мне выразить бла­ годарность А лехан дро А рагону (Alejandro Arag6n), Биллу Бакстеру (B ill B axter), Кевину Билеру (K evin Bealer), Тревису Бочеру (Travis Bo ucher), М айку К асиндж ино (M ike Casinghino), Альваро Кастро Касти лья (Alvaro Castro C astilla), Ричарду Чангу (Richard Chang), Дону Клаг стону, Стефану Д илли (Stephan D illy), Кариму Филали (Karim Filali), М ишелю Ф ортину (M ichel Fortin), Д эвиду Х елду (David В. Held), Мише­ лю Х елвенш тейну (M ichiel H elvensteijn), Бернарду Хельеру (Bernard Helyer), Д ж ей сон у Х аузу (Jason House), Сэму Ху (Sam Hu), Томасу Хью­ му (Thomas Hume), Грэму Д ж ек у (Graham St. Jack), Роберту Ж аку (Ro­ b ert Jacques), Кристиану К эмму (C hristian Kamm), Дэниелу Кипу (Dani el Keep), Марку К егелу (Mark Kegel), Ш ону Келли, Максу Хесину (Мах K hesin), Симену Х ьеросу (Sim en Kjaeras), Коди Кёнингеру (Cody Koenin ger), Д енису К ороскину (D enis Koroskin), JIapcy Кюллингстаду (Lars K yllingstad), Игорю Л есику (Igor Lesik), Евгению Летучему (Eugene Le tuchy), П елле М анссону (Pelle Mansson), Миуре М асахиро (Miura Masa hiro), Тим у Мэтьюсу (Tim M atthews), Скотту Мейерсу, Бартошу Милев ски, Ф авзи М охамеду (Fawzi Mohamed), Эллери Ньюкамеру (Ellery New­ comer), Эрику Н иблеру (Eric Niebler), Майку Паркеру (Mike Parker), Д ереку П арнеллу (Derek Parnell), Д ж ерем и Пеллетье (Jeremie Pelletier), Пабло Риполлесу (РаЫо R ipolles), Брэду Робертсу (Brad Roberts), Майк­ л у Р и н н у (M ichael Rynn), Фою Сава (Foy Savas), Кристофу Шардту (C hristof Schardt), Стиву Ш вайхофферу (Steve Schveighoffer), Бенджа­ м ину Ш ропширу (Benjam in Shropshire), Дэвиду Симше (David Simcha), Томаш у Стаховяку (Tomasz Stachowiak), Роберту Стюарту (Robert Stew art), К нуту Эрику Тайгену (K nut Erik Teigen), Кристиану Влащану (C ristian V lasceanu) и Леору Золм ану (Leor Zolman).

Андрей Александреску Воскресенье 2 мая 2010 г.

Знакомство с языком D Вы ведь знаете, с чего обычно начинают, так что без л иш них слов:

import s t d. s t d i o ;

void main() { w r i t e l n ( "Hello, worl d!' );

} В зависимости от того, какие ещ е языки вы знаете, у вас мож ет возник­ нуть ощущение дежавю, чувство легкой благодарности за простоту, а мо жеу, и легкого разочарования из-за того, что D не пошел по стопам скрип­ товых языков, разрешающих использовать «корневые» (top-level) ин­ струкции. (Такие инструкции побуж даю т вводить глобальные перемен­ ные, которые по мере роста программы превращаются в головную боль;

на самом деле, D позволяет исполнять код не только внутри, но и вне функции main, хотя и более организованно.) Самые въедливые будут ра­ ды узнать, что void main - это эквивалент ф ункции i nt main, возвращ аю­ щей операционной системе «успех» (код 0) при успеш ном окончании ее выполнения.

Но не будем забегать вперед. Т радиционная программа типа «Hello, worldU («Здравствуй, мир!») - вовсе не повод для обсуж дения возм ож ­ ностей языка. Она здесь для того, чтобы помочь вам начать писать и за­ пускать программы на этом язы ке. Если у вас нет никакой IDE, кото­ рая выполнит за вас сборку программы, то самый простой способ - это командная строка. Напечатав приведенный код и сохранив его в файле с именем, скаж ем, hello.d, запустите консоль и введите следую щ ие ко­ манды:

$ dmd h e l l o. d $./h ello H e llo, world!

_ $ 30 Глава 1. Знакомство с языком D Знаком $ обозначено приглаш ение консоли вашей ОС (это может быть с:\Путь\К\Папке в W indow s или /путь/к/каталогу% в системах семейства U N IX, таких как OSX, L inux, Cygwin). Применив пару известных вам приемов систем-фу, вы см ож ете добиться автоматической компиляции программы при ее запуске. Пользователи W indows, вероятно, захотят привязать программу rdmd.exe (которая устанавливается вместе с ком­ пилятором D) к команде В ы п о л н и т ь. U N IX -подобные системы поддержи­ вают запуск скриптов в нотации «shebang»1. D понимает такой синтак­ сис: добавление строки #!/usr/bin/ rdmd в самое начало программы в файле hello.d позволяет компилировать ее автоматически перед исполнением. Внеся это изменение, просто введи­ те в командной строке:

$ chmod u+x h e l l o. d $./h ello.d H e l l o, w orld !

_ $ (chmod нуж н о ввести только один раз).

Д ля всех операционных систем справедливо следующее: программа rdmd достаточно «умна», для того чтобы кэшировать сгенерированное прило­ ж ен ие. Так что фактически компиляция выполняется только после из­ менения исходного кода программы, а не при каж дом запуске. Эта осо­ бенность в сочетании с высокой скоростью самого компилятора позво­ ляет экономить время на зап уск ах программы м еж ду внесением в нее изменений, что одинаково полезно как при разработке больших систем, так и при написании маленьких скриптов.

Программа hello.d начинается с инструкции import s t d. s t d i o ;

которая предписывает компилятору найти модуль с именем std.stdio и сделать его символы доступны ми для использования. Инструкция import напоминает препроцессорную директиву #include, которую мож­ но встретить в синтаксисе С и С++, но семантически она ближ е команде import язы ка Python: никакой вставки текста подключаемого модуля в текст основной программы не происходит - выполняется только про­ стое расш ирение таблицы символов. Если повторно применить инструк­ цию import к тому ж е файлу, ничего не произойдет.


По давней традиции С программа на D представляет собой набор опре­ делений, рассредоточенный по множ еству файлов. В числе прочего эти определения могут обозначать типы, функции, данные. В нашей первой «Shebang» (от shell bang: shell - консоль, bang - восклицательный знак), или «shabang» (# - sharp) - обозначение пути к компилятору или интерпрета­ тору в виде й!/путь/к/программе. - Прим. пер.

1.1. Числа и выражения программе определена функция main. Она не принимает никаких аргу­ ментов и ничего не возвращает, что, по сути, и означает слово void. При выполнении main программа вызывает функцию writeln (разум еется, предусмотрительно определенную в модуле std.stdio), передавая ей стро­ ковую константу в качестве аргумента. Суффикс ln указывает на то, что writeln добавляет к выводимому тексту знак перевода строки.

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

1.1. Числа и выражения Интересовались ли вы когда-нибудь ростом иностранцев? Д авайте на­ пишем простую программу, которая переводит наиболее распростра­ ненные значения роста в ф утах и дю йм ах в сантиметры.

/* Рассчитать значения роста в сантиметрах для заданного диапазона значений в футах и дюймах */ import st d. s t di o ;

void main() { / / Значения, которые никогда не изменятся immutable inchesPerFoot = 12;

immutable cmPerInch = 2.54;

/ / Перебираем и пишем foreach (feet;

5 7) { foreach (inches;

0 inchesPerFoot) { wr i t el n ( f e e t,..... inches, - - \ t " ( f e et * inchesPerFoot + inches) * cmPerInch;

} } В результате выполнения программы будет напечатан аккуратны й спи­ сок в две колонки:

5'0 152. ' 154. 5 11 ’ ' 157. 5 2 ’ 6 110 • ' 208. 210. 6 • 1 1 Инструкция foreach (feet;

5..7) {...} - это цикл, где определена целочис­ ленная переменная feet, с которой последовательно связываются значе­ ния 5 и 6 (значение 7 она не принимает, так как интервал открыт справа).

32 Глава 1. Знакомство с языком D Как и Java, С ++ и C #, D поддерживает /* многострочные комментарии */ и / / однострочные комментарии (и, кроме того, документирующ ие коммен­ тарии, о которых позж е). Еще одна интересная деталь нашей малень­ кой программы - способ объявления данны х. Во-первых, введены две константы:

immutable inchesPerFoot = 12;

immutable cmPerInch = 2.54;

Константы, значения которых никогда не изменятся, определяются с помощью ключевого слова immutable. Как и переменные, константы не требуют явного задания типа: тип задается значением, которым ини­ циализируется константа или переменная. В данном случае литерал говорит компилятору о том, что inchesPerFoot —это целочисленная кон­ станта (обозначается в D с помощью знакомого int);

точно так ж е лите­ рал 2.54 заставляет cmPerInch стать константой с плавающей запятой (типа double). Д алее мы обнаруживаем те ж е магические способности у определений f e et и inches: они выглядят как «обычные» переменные, но безо всяких «украшений», свидетельствующ их о каком-либо типе.

Это не делает программу менее безопасной по сравнению с той, где типы переменных и констант заданы явно:

immutable int inchesPerFoot = 12;

immutable double cmPerInch = 2.54;

foreach (int feet;

5 7) { } и так дал ее —только меньше лиш него. Компилятор разрешает не ука­ зывать тип явно только в случае, когда можно недвусмысленно опреде­ лить его по контексту. Раз у ж заш ла речь о типах, давайте остановимся и посмотрим, какие числовые типы нам доступны.

Ц елые типы со знаком в порядке возрастания размера: byte, short, int и long, заним аю щ ие 8, 16, 32 и 64 бита соответственно. У каждого из эти х типов есть «двойник» без знака того ж е размера, названный в соот­ ветствии с простым правилом: ubyte, ushort, uint и ulong. (Здесь нет мо­ дификатора unsigned, как в С). Типы с плавающей запятой: f loat (32-бит ное число одинарной точности в формате IEEE 754), double (64-битное в формате IEEE 754) и r eal (занимает столько, сколько позволяют реги­ стры, предназначенны е для хранения чисел с плавающей запятой, но не меньше 64 бит;

например, на компьютерах фирмы Intel real - это так называемое расш иренное 79-битное число двойной точности в формате IEEE 754).

Вернемся к наш им целым числам. Литералы, такие как 42, подходят под определение любого числового типа, но заметим, что компилятор проверяет, достаточно ли вместителен «целевой» тип для этого значе­ ния. П оэтому определение immutable byte inchesPerFoot = 12;

1.1. Числа и выражения ничем не хуж е аналогичного без byte, поскольку 12 мож но с таким ж е успехом представить 8 битами, а не 32. По умолчанию, если вывод о «це­ левом» типе делается по числу (как в программе-примере), целочислен­ ные константы «воспринимаются» как in t, а дробные - как double.

Вы можете построить множ ество выражений на D, используя эти типы, арифметические операторы и функции. Операторы и их приоритеты сходны с теми, что можно найти в языках-собратьях D: +, -, *, / и %для базовых арифметических операций, ==, !=,,, =, = для сравнений, fun(argument1, argument2) для вызовов функций и т.д.

Вернемся к нашей программе перевода дюймов в сантиметры и отм е­ тим две достойные внимания детали вызова ф ункции writeln. Первая:

во writeln передаются 5 аргументов (а не один, как в той программе, что установила контакт м еж ду вами и миром D). Ф ункция writeln очень похожа на средства ввода-вывода, встречающ иеся в язы к ах Паскаль (writeln), С (printf) и С++ (cout). Все они (включая writeln и з D) принима­ ют переменное число аргументов (так называемые ф ункции с перемен­ ным числом аргументов). Однако в D пользователи могут определять собственные функции с переменным числом аргументов (чего нет в П ас­ кале), которые всегда типизированы (в отличие от С), без излиш него пе­ реопределения операторов (как это сделано в С++). Вторая деталь: наш вызов writeln неуклю ж е сваливает в кучу информацию о форматирова­ нии и форматируемые данные. Обычно желательно отделять данны е от представления. Поэтому давайте используем специальную функцию writefln, осущ ествляющ ую форматированный вывод:

writefln("%s' %s' ' \t%s", fee t, inches, (feet * inchesPerFoot + inches) * cmPerInch) ;

По-новому организованный вызов дает тот ж е вывод, но первый аргу­ мент функции writefln полностью описывает формат представления. Со знака %начинаются спецификаторы формата (по аналогии с ф ункцией pr in tf из С): например % - для целы х чисел, %f - для чисел с плаваю ­ d щей запятой и %s —для строк.

Если вы использовали p r i n t f преж де, то могли бы почувствовать себя как дома, когда б не маленькая особенность: мы ведь выводим значения переменных типа int и double - как ж е получилось, что и те и другие описаны с помощью спецификатора %s, обычно применяемого для выво­ да строк? Ответ прост. Средства D для работы с переменным количест­ вом аргументов дают wri tefln доступ к информации об исходны х типах переданных аргументов. Благодаря такому подходу программа получа­ ет ряд преимуществ: 1) значение %s мож ет быть расш ирено до «строко­ вого представления по умолчанию для типа переданного аргумента»

и 2) если не удалось сопоставить спецификатор формата с типами пере­ данных аргументов, вы получите ош ибку в чистом виде, а не загадоч­ ное поведение, присущ ее вызовам p r i n t f с неверно заданны м форматом (не говоря уж е о подрыве безопасности, возможном при вызове p r i n t f с непроверяемыми заранее форматирующ ими строками).

34 Глава 1. Знакомство с языком D 1.2. Инструкции В язы ке D, как и в др уги х родственных ему язы ках, любое выражение, после которого стоит точка с запятой, - это инструкция (например в программе «Hello, world!» сразу после вызова writ eln есть ;

). Действие инструкции сводится к вычислению выражения.

D - член семейства с фигурны ми скобками и с блочной областью види­ мости». Это означает, что вы мож ете объединять несколько команд в од­ ну, помещ ая и х в { и }, что порой обязательно, например при желании сделать сразу несколько вещей в цикле foreach. В случае единственной команды вы вправе смело опустить фигурные скобки. На самом деле, весь наш двойной цикл, вычисляющ ий значения роста, можно перепи­ сать так:

foreach ( f e et ;

5 7) foreach (inches;

0 inchesPerFoot) wr i tef l n( "%s' %s' '\ t %s" fee t, inches, ( f e e t * inchesPerFoot + inches) * cmPerInch);

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

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

Благодаря язы ку P ython стал популярен иной способ отражения блоч­ ной структуры программы - с помощью отступов (чудесное воплоще­ ние принципа «форма соответствует содержанию»). Для программистов на други х язы ках утверж дение, что пробел имеет значение, - всего лиш ь нелепая фраза, но для тех, кто пишет на Python, это зарок. D обыч­ но игнорирует пробелы, но он разработан с прицелом на легкость син­ таксического разбора (т. e. чтобы при разборе не приходилось выяснять значения символов). А это подразумевает, что в рамках скромного «ком­ натного» проекта м ож но реализовать простой препроцессор, позволяю­ щ ий использовать для выделения блоков инструкций отступы (как в P ython) без каких-либо неудобств во время компиляции, исполнения и отладки программ.

Кроме того, вам дол ж н а быть хорошо знакома инструкция if:

i f ('выражение) инструкция, e l s e инструкцияг 1.3. Основы работы с функциями Чисто теоретический вывод, известный как принцип структурного про­ граммирования [10], гласит, что все алгоритмы можно реализовать с по­ мощью составных инструкций, if-проверок и циклов а-ля for и foreach.

Разумеется, любой адекватный язы к (как и D) предлагает гораздо боль­ ше, но мы пока постановим, что с нас довольно и этих инструкций, и двинемся дальше.

1.3. Основы работы с функциями Оставим пока в стороне обязательное определение функции main и по­ смотрим, как определяются другие ф ункции на D. Определение ф унк­ ции соответствует модели, характерной и для других Алгол-подобных языков: сначала пиш ется возвращаемый тип, потом имя ф ункции и, наконец, заключенный в круглые скобки список формальных аргумен­ тов, разделенных запятыми. Например, определение ф ункции с им е­ нем pow, которая принимает значения типа double и in t, а возвращает double, записывается так:

double pow(double base, int exponent) { } Каждый параметр ф ункции (base и exponent в данном примере) кроме типа может иметь необязательный класс пам ят и (storage class), опре­ деляющий способ передачи аргумента в функцию при ее вызове1.

По умолчанию аргументы передаются в pow по значению. Если перед типом параметра указан класс памяти ref, то параметр привязывается напрямую к входному аргументу, так что изменение параметра непо­ средственно отраж ается на значении, полученном извне. Например:

import std.stdio;

void fun(ref uint x, double у) { x = 42;

у = 3.14;

} void main() { uint а = 1;

double b = 2;

funa, b);

writeln(a, '' " b);

} Эта программа печатает 42 2, потому что x определен как ref uint, то есть когда значение присваивается x, на самом деле операция проводит­ ся с а. С другой стороны, присваивание значения переменной у никак 1 В этой книге под «параметром» понимается значение, используемое внутри функции, а под «аргументом» - значение, передаваемое в функцию извне.

36 Глава 1. Знакомство с языком D не скаж ется на b, поскольку у - это внутренняя копия в распоряжении ф ункции fun.

П оследние *украш ения», которые мы обсудим в этом кратком введе­ нии, - это i n и o u t. П опросту говоря, in - данное функцией «обещание»

только смотреть на параметр, не «трогая» его. Указание out в определе­ нии параметра ф ункции действует сходно с ref, с той поправкой, что па­ раметр принудительно инициализируется своим значением по умолча­ нию при «входе» в функцию. (Для каж дого типа T определено началь­ ное значение, обозначаемое как T. i n i t. Пользовательские типы могут определять собственное значение по умолчанию.) О ф ун кц иях м ож но ещ е долго рассказывать. Можно передавать функ­ ции другим ф ункциям, встраивать одну в другую, разрешать функции сохранять свою локальную среду (полнофункциональная синтаксиче­ ская клауза), создавать анонимные функции (лямбда-функции), с удоб­ ством манипулировать ими и ещ е множество дополнительных «вкусно­ стей». Со временем мы доберемся до каж дой из них.

1.4. Массивы и ассоциативные массивы Массивы и ассоциативные массивы (которые обычно называют хеш-таб­ лицами, или хеш ами) —пож алуй, наиболее часто используемые слож­ ные структуры данны х за всю историю маш инных вычислений, завист­ ливо преследуемые списками языка Лисп. Множество полезных про­ грамм не требуют ничего, кроме массива или ассоциативного массива.

Так что пришло время посмотреть, как D их реализует.

1.4.1. Работаем со словарем Д ля примера напиш ем простенькую программку, следуя такой специ­ фикации:

Читать текст, состоящий из слов, разделенных пробелами, и сопоставлять каждому не встречавшемуся до сих пор при чтении слову уникальное чис­ ло. Вывод организовать в виде строк формата:

идентификатор слово Такой маленький скрипт вполне м ож ет пригодиться, когда вы захотите обработать какой-нибудь текст. Построив словарь, вы получите возмож­ ность манипулировать только числами (что дешевле), а не полновесны­ ми словами. Один из вариантов построения такого словаря - накапли­ вать у ж е прочитанные слова в ассоциативном массиве, отображающем слова на целые числа. При добавлении нового соответствия достаточно убедиться, что число, связываемое со словом, уникально («железная»

гарантия - просто использовать текущ ую длину массива, в результате чего получится последовательность идентификаторов 0, 1, 2,...). По­ смотрим, как это мож но реализовать на D.

1.4. Массивы и ассоциативные массивы import s t d. st d i o, s t d. s t r i n g ;

void main() slze_t [ s t r i n g ] dictionary;

foreach ( line;

st di n. by L i ne Q) { / / Разбить строку на слова / / Добавить каждое слово строки в словарь foreach (word;

s p l i t t e r ( s t r i p ( l i n e ) )) { if (word in di c ti ona ry ) continue;

/ / Ничего не делать auto newID = d ic ti o na ry. l e n g th ;

dictionary[word.idup] = newID;

writeln(newID, ' \ t ' word);

} } } В языке D ассоциативный массив (хеш-таблица), который значениям типа К ставит в соответствие значения типа V обозначается как V[K].

, Итак, переменная dict ionary типа s i z e _ t [s t ri n g] сопоставляет строкам целые числа без знака - как раз то, что нам нуж но для хранения соот ветствийсловидентификаторам.Вы раж ениеую гс! in d i c t i on ar y n cT H H но, если ключевое слово word мож но найти в ассоциативном массиве dictionary. Наконец, вставкавсловарьвы полняется так: dictionary[word.

idup] = newID1.

Хотя в рассмотренном сценарии не отраж ается явно тот факт, что тип s t r i n g - на самом деле массив знаков, это так. В общем виде динам иче­ ский массив элементов типа T обозначается как T[ ] и м ож ет определять­ ся различными способами:

int[] а = new int[20];

/ / 20 целых чисел, инициализированных нулями int[] b = [ 1, 2, 3 ];

/ / Массив, содержащий 1, 2, и В отличие от массивов С, массивы D «знают» собственную длину. Для любого массива arr это значение доступно как arr.length. П рисваивание значения arr.length перераспределяет память, вы деленную под массив.

При попытке обращения к элементам массива проверяется, не выходит ли запрашиваемый индекс за границу массива. Лю бители рискнуть пе­ реполнением буфера могут «выдрать» указатель из массива (используя arr.ptr) и затем выполнять непроверенные арифметические операции над ним. Кроме того, если вам действительно нуж н о все, что м ож ет дать кремниевая пластина, есть опция компилятора, отменяю щ ая проверку границ. Можно сказать, что к безопасности ведет путь наименьш его со­ противления. Код безопасен по умолчанию, а если поработать, мож но сделать его чуть более быстрым.

.idup - свойство любого массива, возвращающее неизменяемую (immutable) копию массива. Про неизменяемость будет рассказано позже, пока же сле­ дует знать, что ключ ассоциативного массива должен быть неизменяемым. — Прим. науч. ред.

38 Глава 1. Знакомство с языком D Вот как мож но проходить по массиву с помощью новой формы уж е зна­ комой инструкции foreach:

i n t [ ] a r r = new i nt[ 20] ;

foreach (elem;

a r r ) { /*... использовать elem. •/ } Этот цикл по очереди связывает переменную elem с каж ды м элементом массива arr. Присваивание elem не влияет на элементы arr. Чтобы изме­ нить массив таким способом, просто используйте ключевое слово ref:

/ / Обнулить все элементы ar r foreach ( re f elem;

a r r ) { elem = 0;

} Теперь, когда мы знаем, как foreach работает с массивами, рассмотрим ещ е один полезный прием. Если в теле цикла вам потребуется индекс элемента массива, foreach м ож ет рассчитать его для вас:

l n t [ ] months = new int [ 1 2] ;

foreach ( i, ref e;

months) { e = i + 1;

} Этот код заполняет массив числами от 1 до 12. Такой цикл эквивален­ тен чуть более многословному определению (см. ниже), использующему foreach для просмотра диапазона чисел:

foreach ( i ;

0 months.length) { months[i] = i + 1;

D так ж е предлагает массивы фиксированного размера, обозначаемые, например, как in t[5]. За исключением отдельных специализирован­ ны х прилож ений, предпочтительнее использовать динамические мас­ сивы, поскольку обычно размер массива вам заранее неизвестен.

Семантика копирования массивов неочевидна: копирование одной пе­ ременной типа массив в другую не копирует весь массив;

эта операция порож дает лиш ь новую ссылку на ту ж е область памяти. Если вам дей­ ствительно хочется заполучить копию, просто используйте свойство массива.dup:

i n t [ ] а = new int[100];

i n t [ ] b = а;

/ / ++x увеличивает на 1 значение x ++b[10];

/ / В b[10] теперь 1, в a[10] то же b = a.dup;

/ / Полностью скопировать а в b ++b[10];

/ / В b[10] теперь 2, а в a[10] остается 1.4. Массивы и ассоциативные массивы 1.4.2. Получение среза массива.

Функции с обобщенными типами параметров.

Тесты модулей Получение среза массива - это мощ ное средство, позволяющ ее ссылать­ ся на часть массива, в действительности не копируя данные массива.



Pages:   || 2 | 3 | 4 | 5 |   ...   | 15 |
 





 
© 2013 www.libed.ru - «Бесплатная библиотека научно-практических конференций»

Материалы этого сайта размещены для ознакомления, все права принадлежат их авторам.
Если Вы не согласны с тем, что Ваш материал размещён на этом сайте, пожалуйста, напишите нам, мы в течении 1-2 рабочих дней удалим его.