Alexander 2 лет назад
Родитель
Сommit
b2bfe5c7a1
1 измененных файлов с 44 добавлено и 3 удалено
  1. 44 3
      01-знакомство-с-языком-d/README.md

+ 44 - 3
01-знакомство-с-языком-d/README.md

@@ -1,8 +1,8 @@
 # 1. Знакомство с языком D
 
-- [1.1. Числа и выражения](#11-числа-и-выражения)
-- [1.2. Инструкции](#12-инструкции)
-- [1.3. Основы работы с функциями]()
+- [1.1. Числа и выражения](#1-1-числа-и-выражения)
+- [1.2. Инструкции](#1-2-инструкции)
+- [1.3. Основы работы с функциями](#1-3-основы-работы-с-функциями)
 - 1.4. Массивы и ассоциативные массивы
 - [1.4.1. Работа со словарем]()
 - [1.4.2. Получение среза массива. Функции с обобщенными типами параметров. Тесты модулей]()
@@ -178,4 +178,45 @@ if (‹выражение›) ‹инструкция1› else ‹инструк
 
 Чисто теоретический вывод, известный как принцип структурного программирования, гласит, что все алгоритмы можно реализовать с помощью составных инструкций, `if`-проверок и циклов а-ля `for` и `foreach`. Разумеется, любой адекватный язык (как и D) предлагает гораздо больше, но мы пока постановим, что с нас довольно и этих инструкций, и двинемся дальше.
 
+## 1.3. Основы работы с функциями
+
+Оставим пока в стороне обязательное определение функции `main` и посмотрим, как определяются другие функции на D. Определение функции соответствует модели, характерной и для других Алгол-подобных языков: сначала пишется возвращаемый тип, потом имя функции и, наконец, заключенный в круглые скобки список формальных аргументов, разделенных запятыми. Например, определение функции с именем `pow`, которая принимает значения типа `double` и `int`, а возвращает `double`, записывается так:
+
+```d
+double pow(double base, int exponent)
+{
+    ...
+}
+```
+
+Каждый параметр функции (`base` и `exponent` в данном примере) кроме типа может иметь необязательный ***класс памяти*** (***storage class***), определяющий способ передачи аргумента в функцию при ее вызове[^2].
+
+По умолчанию аргументы передаются в `pow` по значению. Если перед типом параметра указан класс памяти `ref`, то параметр привязывается напрямую к входному аргументу, так что изменение параметра непосредственно отражается на значении, полученном извне. Например:
+
+```d
+import std.stdio;
+
+void fun(ref uint x, double y)
+{
+    x = 42;
+    y = 3.14;
+}
+
+void main()
+{
+    uint a = 1;
+    double b = 2;
+    fun(a, b);
+    writeln(a, " ", b);
+}
+
+```
+
+Эта программа печатает `42 2`, потому что `x` определен как `ref uint`, то есть когда значение присваивается x, на самом деле операция проводится с `a`. С другой стороны, присваивание значения переменной `y` никак не скажется на `b`, поскольку `y` – это внутренняя копия в распоряжении функции `fun`.
+
+Последние «украшения», которые мы обсудим в этом кратком введении, – это `in` и `out`. Попросту говоря, `in` – данное функцией «обещание» только смотреть на параметр, не «трогая» его. Указание `out` в определении параметра функции действует сходно с `ref`, с той поправкой, что параметр принудительно инициализируется своим значением по умолчанию при «входе» в функцию. (Для каждого типа `T` определено начальное значение, обозначаемое как `T.init`. Пользовательские типы могут определять собственное значение по умолчанию.)
+
+О функциях можно еще долго рассказывать. Можно передавать функции другим функциям, встраивать одну в другую, разрешать функции сохранять свою локальную среду (полнофункциональная синтаксическая клауза), создавать анонимные функции (лямбда-функции), с удобством манипулировать ими и еще множество дополнительных «вкусностей». Со временем мы доберемся до каждой из них.
+
 [^1]: «Shebang» (от shell bang: shell – консоль, bang – восклицательный знак), или «shabang» (# – sharp) – обозначение пути к компилятору или интерпретатору в виде `#!/путь/к/программе`. – *Прим. пер.*
+[^2]: В этой книге под «параметром» понимается значение, используемое внутри функции, а под «аргументом» – значение, передаваемое в функцию извне.