fix
This commit is contained in:
parent
4be7b9c4ce
commit
50df530401
|
@ -67,7 +67,8 @@ import std.stdio;
|
||||||
Следующие разделы – это стремительная поездка по Дибургу. Небольшие показательные программы дают общее представление о языке. Основная цель повествования на данном этапе – обрисовать общую картину, а не дать ряд педантичных определений. Позже все аспекты языка будут рассмотрены с должным вниманием – в деталях.
|
Следующие разделы – это стремительная поездка по Дибургу. Небольшие показательные программы дают общее представление о языке. Основная цель повествования на данном этапе – обрисовать общую картину, а не дать ряд педантичных определений. Позже все аспекты языка будут рассмотрены с должным вниманием – в деталях.
|
||||||
|
|
||||||
[Исходный код](src/chapter-1/)
|
[Исходный код](src/chapter-1/)
|
||||||
[В начало ⮍](#1-знакомство-с-языком-d) [Наверх ⮍](#1-знакомство-с-языком-d)
|
|
||||||
|
[В начало ⮍](#1-знакомство-с-языком-d)
|
||||||
|
|
||||||
## 1.1. Числа и выражения
|
## 1.1. Числа и выражения
|
||||||
|
|
||||||
|
@ -150,6 +151,7 @@ writefln("%s'%s''\t%s", feet, inches, (feet * inchesPerFoot + inches) * cmPerInc
|
||||||
Если вы использовали `printf` прежде, то могли бы почувствовать себя как дома, когда б не маленькая особенность: мы ведь выводим значения переменных типа `int` и `double` – как же получилось, что и те и другие описаны с помощью спецификатора `%s`, обычно применяемого для вывода строк? Ответ прост. Средства D для работы с переменным количеством аргументов дают `writefln` доступ к информации об исходных типах переданных аргументов. Благодаря такому подходу программа получает ряд преимуществ: 1) значение `%s` может быть расширено до «строкового представления по умолчанию для типа переданного аргумента» и 2) если не удалось сопоставить спецификатор формата с типами переданных аргументов, вы получите ошибку в чистом виде, а не загадочное поведение, присущее вызовам `printf` с неверно заданным форматом (не говоря уже о подрыве безопасности, возможном при вызове `printf` с непроверяемыми заранее форматирующими строками).
|
Если вы использовали `printf` прежде, то могли бы почувствовать себя как дома, когда б не маленькая особенность: мы ведь выводим значения переменных типа `int` и `double` – как же получилось, что и те и другие описаны с помощью спецификатора `%s`, обычно применяемого для вывода строк? Ответ прост. Средства D для работы с переменным количеством аргументов дают `writefln` доступ к информации об исходных типах переданных аргументов. Благодаря такому подходу программа получает ряд преимуществ: 1) значение `%s` может быть расширено до «строкового представления по умолчанию для типа переданного аргумента» и 2) если не удалось сопоставить спецификатор формата с типами переданных аргументов, вы получите ошибку в чистом виде, а не загадочное поведение, присущее вызовам `printf` с неверно заданным форматом (не говоря уже о подрыве безопасности, возможном при вызове `printf` с непроверяемыми заранее форматирующими строками).
|
||||||
|
|
||||||
[Исходный код](src/chapter-1-1/)
|
[Исходный код](src/chapter-1-1/)
|
||||||
|
|
||||||
[В начало ⮍](#1-1-числа-и-выражения) [Наверх ⮍](#1-знакомство-с-языком-d)
|
[В начало ⮍](#1-1-числа-и-выражения) [Наверх ⮍](#1-знакомство-с-языком-d)
|
||||||
|
|
||||||
## 1.2. Инструкции
|
## 1.2. Инструкции
|
||||||
|
@ -186,6 +188,7 @@ if (‹выражение›) ‹инструкция1› else ‹инструк
|
||||||
Чисто теоретический вывод, известный как принцип структурного программирования, гласит, что все алгоритмы можно реализовать с помощью составных инструкций, `if`-проверок и циклов а-ля `for` и `foreach`. Разумеется, любой адекватный язык (как и D) предлагает гораздо больше, но мы пока постановим, что с нас довольно и этих инструкций, и двинемся дальше.
|
Чисто теоретический вывод, известный как принцип структурного программирования, гласит, что все алгоритмы можно реализовать с помощью составных инструкций, `if`-проверок и циклов а-ля `for` и `foreach`. Разумеется, любой адекватный язык (как и D) предлагает гораздо больше, но мы пока постановим, что с нас довольно и этих инструкций, и двинемся дальше.
|
||||||
|
|
||||||
[Исходный код](src/chapter-1-2/)
|
[Исходный код](src/chapter-1-2/)
|
||||||
|
|
||||||
[В начало ⮍](#1-2-инструкции) [Наверх ⮍](#1-знакомство-с-языком-d)
|
[В начало ⮍](#1-2-инструкции) [Наверх ⮍](#1-знакомство-с-языком-d)
|
||||||
|
|
||||||
## 1.3. Основы работы с функциями
|
## 1.3. Основы работы с функциями
|
||||||
|
@ -229,6 +232,7 @@ void main()
|
||||||
О функциях можно еще долго рассказывать. Можно передавать функции другим функциям, встраивать одну в другую, разрешать функции сохранять свою локальную среду (полнофункциональная синтаксическая клауза), создавать анонимные функции (лямбда-функции), с удобством манипулировать ими и еще множество дополнительных «вкусностей». Со временем мы доберемся до каждой из них.
|
О функциях можно еще долго рассказывать. Можно передавать функции другим функциям, встраивать одну в другую, разрешать функции сохранять свою локальную среду (полнофункциональная синтаксическая клауза), создавать анонимные функции (лямбда-функции), с удобством манипулировать ими и еще множество дополнительных «вкусностей». Со временем мы доберемся до каждой из них.
|
||||||
|
|
||||||
[Исходный код](src/chapter-1-3/)
|
[Исходный код](src/chapter-1-3/)
|
||||||
|
|
||||||
[В начало ⮍](#1-3-основы-работы-с-функциями) [Наверх ⮍](#1-знакомство-с-языком-d)
|
[В начало ⮍](#1-3-основы-работы-с-функциями) [Наверх ⮍](#1-знакомство-с-языком-d)
|
||||||
|
|
||||||
## 1.4. Массивы и ассоциативные массивы
|
## 1.4. Массивы и ассоциативные массивы
|
||||||
|
@ -336,6 +340,7 @@ b = a.dup; // Полностью скопировать a в b
|
||||||
```
|
```
|
||||||
|
|
||||||
[Исходный код](src/chapter-1-4-1/)
|
[Исходный код](src/chapter-1-4-1/)
|
||||||
|
|
||||||
[В начало ⮍](#1-4-1-работаем-со-словарем) [Наверх ⮍](#1-знакомство-с-языком-d)
|
[В начало ⮍](#1-4-1-работаем-со-словарем) [Наверх ⮍](#1-знакомство-с-языком-d)
|
||||||
|
|
||||||
### 1.4.2. Получение среза массива. Функции с обобщенными типами параметров. Тесты модулей
|
### 1.4.2. Получение среза массива. Функции с обобщенными типами параметров. Тесты модулей
|
||||||
|
@ -400,6 +405,7 @@ bool binarySearchR(T)(T[] input, T value)
|
||||||
Рекурсивная реализация явно проще и концентрированнее по сравнению со своим итеративным собратом. Кроме того, она ничуть не менее эффективна, так как рекурсивные вызовы оптимизируются благодаря популярной среди компиляторов технике, известной как *оптимизация хвостовой рекурсии*. В двух словах: если функция возвращает просто вызов самой себя (но с другими аргументами), компилятор модифицирует аргументы и инициирует переход к началу функции.
|
Рекурсивная реализация явно проще и концентрированнее по сравнению со своим итеративным собратом. Кроме того, она ничуть не менее эффективна, так как рекурсивные вызовы оптимизируются благодаря популярной среди компиляторов технике, известной как *оптимизация хвостовой рекурсии*. В двух словах: если функция возвращает просто вызов самой себя (но с другими аргументами), компилятор модифицирует аргументы и инициирует переход к началу функции.
|
||||||
|
|
||||||
[Исходный код](src/chapter-1-4-2/)
|
[Исходный код](src/chapter-1-4-2/)
|
||||||
|
|
||||||
[В начало ⮍](#1-4-2-получение-среза-массива-функции-с-обобщенными-типами-параметров-тесты-модулей) [Наверх ⮍](#1-знакомство-с-языком-d)
|
[В начало ⮍](#1-4-2-получение-среза-массива-функции-с-обобщенными-типами-параметров-тесты-модулей) [Наверх ⮍](#1-знакомство-с-языком-d)
|
||||||
|
|
||||||
### 1.4.3. Подсчет частот. Лямбда-функции
|
### 1.4.3. Подсчет частот. Лямбда-функции
|
||||||
|
@ -510,6 +516,7 @@ sort!(‹аргументы времени компиляции›)(‹аргу
|
||||||
Что и ожидалось: самые часто употребляемые слова набрали больше всего «очков». Настораживает лишь «Ham»[^7]. Это слово в пьесе вовсе не отражает кулинарные предпочтения героев. «Ham» – всего лишь сокращение от «Hamlet» (Гамлет), которым помечена каждая из его реплик. Явно у него был повод высказаться 358 раз – больше, чем любой другой герой пьесы. Далее по списку следует король – всего 116 реплик, меньше трети сказанного Гамлетом. А Офелия с ее 58 репликами – просто молчунья.
|
Что и ожидалось: самые часто употребляемые слова набрали больше всего «очков». Настораживает лишь «Ham»[^7]. Это слово в пьесе вовсе не отражает кулинарные предпочтения героев. «Ham» – всего лишь сокращение от «Hamlet» (Гамлет), которым помечена каждая из его реплик. Явно у него был повод высказаться 358 раз – больше, чем любой другой герой пьесы. Далее по списку следует король – всего 116 реплик, меньше трети сказанного Гамлетом. А Офелия с ее 58 репликами – просто молчунья.
|
||||||
|
|
||||||
[Исходный код](src/chapter-1-4-3/)
|
[Исходный код](src/chapter-1-4-3/)
|
||||||
|
|
||||||
[В начало ⮍](#1-4-3-подсчет-частот-лямбда-функции) [Наверх ⮍](#1-знакомство-с-языком-d)
|
[В начало ⮍](#1-4-3-подсчет-частот-лямбда-функции) [Наверх ⮍](#1-знакомство-с-языком-d)
|
||||||
|
|
||||||
## 1.5. Основные структуры данных
|
## 1.5. Основные структуры данных
|
||||||
|
@ -686,6 +693,7 @@ Ambassador 41 34
|
||||||
В выводе есть немного шума (например, `"Both [Mar"`), который прилежный программист легко устранит и который вряд ли статистически влияет на то, что действительно представляет для нас интерес. Тем не менее исправление последних огрехов – поучительное (и рекомендуемое) упражнение.
|
В выводе есть немного шума (например, `"Both [Mar"`), который прилежный программист легко устранит и который вряд ли статистически влияет на то, что действительно представляет для нас интерес. Тем не менее исправление последних огрехов – поучительное (и рекомендуемое) упражнение.
|
||||||
|
|
||||||
[Исходный код](src/chapter-1-5/)
|
[Исходный код](src/chapter-1-5/)
|
||||||
|
|
||||||
[В начало ⮍](#1-5-основные-структуры-данных) [Наверх ⮍](#1-знакомство-с-языком-d)
|
[В начало ⮍](#1-5-основные-структуры-данных) [Наверх ⮍](#1-знакомство-с-языком-d)
|
||||||
|
|
||||||
## 1.6. Интерфейсы и классы
|
## 1.6. Интерфейсы и классы
|
||||||
|
@ -789,6 +797,7 @@ auto newStat = cast(Stat) Object.factory("stats." ~ arg);
|
||||||
Оглянувшись назад, мы заметим, что львиная доля того, что делает скрипт, выполняется в первых пяти его строках. Эта самая сложная часть, которая полностью определяет весь остальной код. Второй цикл читает по одному числу за раз (об этом заботится функция `readf`) и вызывает `accumulate` для всех объектов, собирающих статистику. Функция `readf` возвращает число объектов, успешно прочитанных согласно заданной строке формата. В нашем случае формат задан в виде строки `" %s "`, что означает «один элемент, окруженный любым количеством пробелов». (Тип элемента определяется типом считанного элемента, в нашем случае `x` принимает значение типа `double`.) Последнее, что делает программа, – выводит результаты вычислений на печать.
|
Оглянувшись назад, мы заметим, что львиная доля того, что делает скрипт, выполняется в первых пяти его строках. Эта самая сложная часть, которая полностью определяет весь остальной код. Второй цикл читает по одному числу за раз (об этом заботится функция `readf`) и вызывает `accumulate` для всех объектов, собирающих статистику. Функция `readf` возвращает число объектов, успешно прочитанных согласно заданной строке формата. В нашем случае формат задан в виде строки `" %s "`, что означает «один элемент, окруженный любым количеством пробелов». (Тип элемента определяется типом считанного элемента, в нашем случае `x` принимает значение типа `double`.) Последнее, что делает программа, – выводит результаты вычислений на печать.
|
||||||
|
|
||||||
[Исходный код](src/chapter-1-6/)
|
[Исходный код](src/chapter-1-6/)
|
||||||
|
|
||||||
[В начало ⮍](#1-6-интерфейсы-и-классы) [Наверх ⮍](#1-знакомство-с-языком-d)
|
[В начало ⮍](#1-6-интерфейсы-и-классы) [Наверх ⮍](#1-знакомство-с-языком-d)
|
||||||
|
|
||||||
### 1.6.1. Больше статистики. Наследование
|
### 1.6.1. Больше статистики. Наследование
|
||||||
|
@ -860,6 +869,7 @@ class Average : IncrementalStat
|
||||||
Начнем с того, что в `Average` вводится еще одно поле, `items`, которое инициализируется нулем с помощью синтаксиса `items = 0` (только для того, чтобы показать, как надо инициализировать переменные, но, как отмечалось выше, целые числа и так инициализируются нулем по умолчанию). Второе, что необходимо отметить: `Average` определяет конструктор, который присваивает переменной `_result` ноль. Так сделано, потому что, в отличие от минимума или максимума, при отсутствии аргументов среднее арифметическое считается равным нулю. И хотя может показаться, что инициализировать `_result` значением NaN только для того, чтобы тут же записать в эту переменную ноль, – бессмысленное действие, уход от так называемого «мертвого присваивания» представляет собой легкую добычу для любого оптимизатора. Наконец, `Average` переопределяет метод `postprocess`, несмотря на то что в классе `IncrementalStat` он уже определен. В языке D по умолчанию можно переопределить (унаследовать и заново определить) методы любого класса, но надо обязательно добавлять директиву `override`, чтобы избежать всевозможных несчастных случаев (таких как неудача переопределения в связи с какой-нибудь опечаткой или изменением в базовом типе, либо переопределение чего-нибудь по ошибке). Если вы поставите перед методом класса ключевое слово `final`, то запретите классам-потомкам переопределять эту функцию (что эффективно останавливает механизм динамического поиска методов по дереву классов).
|
Начнем с того, что в `Average` вводится еще одно поле, `items`, которое инициализируется нулем с помощью синтаксиса `items = 0` (только для того, чтобы показать, как надо инициализировать переменные, но, как отмечалось выше, целые числа и так инициализируются нулем по умолчанию). Второе, что необходимо отметить: `Average` определяет конструктор, который присваивает переменной `_result` ноль. Так сделано, потому что, в отличие от минимума или максимума, при отсутствии аргументов среднее арифметическое считается равным нулю. И хотя может показаться, что инициализировать `_result` значением NaN только для того, чтобы тут же записать в эту переменную ноль, – бессмысленное действие, уход от так называемого «мертвого присваивания» представляет собой легкую добычу для любого оптимизатора. Наконец, `Average` переопределяет метод `postprocess`, несмотря на то что в классе `IncrementalStat` он уже определен. В языке D по умолчанию можно переопределить (унаследовать и заново определить) методы любого класса, но надо обязательно добавлять директиву `override`, чтобы избежать всевозможных несчастных случаев (таких как неудача переопределения в связи с какой-нибудь опечаткой или изменением в базовом типе, либо переопределение чего-нибудь по ошибке). Если вы поставите перед методом класса ключевое слово `final`, то запретите классам-потомкам переопределять эту функцию (что эффективно останавливает механизм динамического поиска методов по дереву классов).
|
||||||
|
|
||||||
[Исходный код](src/chapter-1-6-1/)
|
[Исходный код](src/chapter-1-6-1/)
|
||||||
|
|
||||||
[В начало ⮍](#1-6-1-больше-статистики-наследование) [Наверх ⮍](#1-знакомство-с-языком-d)
|
[В начало ⮍](#1-6-1-больше-статистики-наследование) [Наверх ⮍](#1-знакомство-с-языком-d)
|
||||||
|
|
||||||
## 1.7. Значения против ссылок
|
## 1.7. Значения против ссылок
|
||||||
|
@ -905,6 +915,7 @@ void main()
|
||||||
В завершение хочется сказать, что структуры – пожалуй, наиболее гибкое проектное решение. Определив структуру, вы можете вдохнуть в нее любую семантику. Вы можете сделать так, что значение будет копироваться постоянно, реализовать ленивое копирование, а-ля копирование при записи, или подсчитывать ссылки, или выбрать что-то среднее между этими способами. Вы даже можете определить ссылочную семантику, используя классы или указатели *внутри* своей структуры. С другой стороны, некоторые из этих альтернатив требуют подкованности в техническом плане; использование классов, напротив, подразумевает простоту и унифицированность.
|
В завершение хочется сказать, что структуры – пожалуй, наиболее гибкое проектное решение. Определив структуру, вы можете вдохнуть в нее любую семантику. Вы можете сделать так, что значение будет копироваться постоянно, реализовать ленивое копирование, а-ля копирование при записи, или подсчитывать ссылки, или выбрать что-то среднее между этими способами. Вы даже можете определить ссылочную семантику, используя классы или указатели *внутри* своей структуры. С другой стороны, некоторые из этих альтернатив требуют подкованности в техническом плане; использование классов, напротив, подразумевает простоту и унифицированность.
|
||||||
|
|
||||||
[Исходный код](src/chapter-1-7/)
|
[Исходный код](src/chapter-1-7/)
|
||||||
|
|
||||||
[В начало ⮍](#1-7-значения-против-ссылок) [Наверх ⮍](#1-знакомство-с-языком-d)
|
[В начало ⮍](#1-7-значения-против-ссылок) [Наверх ⮍](#1-знакомство-с-языком-d)
|
||||||
|
|
||||||
## 1.8. Итоги
|
## 1.8. Итоги
|
||||||
|
|
Loading…
Reference in New Issue