Функции


Предыдущая страница
Следующая страница  

В этой главе описываются функции, используемые в программировании на D.

Определение функции в D

В своей основе определение функции состоит из заголовка функции и тела функции.

Синтаксис

возвращаемый_тип имя_функции( список_параметров ) { 
   тело_функции 
}

Вот описание всех частей функции:

Вызов функции

Вы можете вызвать функцию следующим образом:

имя_функции(список_параметров)

Типы функций в D

D поддерживает широкий спектр функций, и они перечислены ниже.

Ниже описаны различные функции.

Чистые функции

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

import std.stdio; 

int x = 10; 
immutable int y = 30; 
const int* p;  

pure int purefunc(int i,const char* q,immutable int* s) { 
   //writeln("Simple print"); //нельзя вызывать "нечистую" функцию 'writeln'
   
   debug writeln("in foo()"); // можно, "нечистый" код допустим в операторе debug 
   // x = i;  // ошибка, изменение глобального состояния 
   // i = x;  // ошибка, чтение изменяемого глобального состояния 
   // i = *p; // ошибка, чтение константного глобального состояния 
   i = y;     // можно, чтение неизменяемого глобального состояния 
   auto myvar = new int;     // Можно использовать выражение new 
   return i; 
}

void main() { 
   writeln("Значение, возвращаемое из чистой функции : ",purefunc(x,null,null)); 
}

Когда вы скомпилируете и выполните эту программу, она возвратит следующий результат:

Значение, возвращаемое из чистой функции : 30

Функции Nothrow

Функции Nothrow не выбрасывают никаких исключений, унаследованных от класса Exception.

Nothrow гарантирует, что функция не выбрасывает никаких исключений.

import std.stdio; 

int add(int a, int b) nothrow { 
   //writeln("сложение"); Это не удастся, потому что writeln может бросать исключения 
   int result; 
   
   try { 
      writeln("сложение"); // компилируется 
      result = a + b; 
   } catch (Exception error) { // ловит все исключения 
   }

   return result; 
} 
 
void main() { 
   writeln("Результат сложения: ", add(10,20)); 
}

Когда вы скомпилируете и выполните эту программу, она возвратит следующий результат:

сложение
Результат сложения: 30

Ref-Функции

Ref-Функции позволяют возвращать значение функции по ссылке. Это аналогично ref-параметрам функции.

import std.stdio;

// "greater" переводится как "больший" 
ref int greater(ref int first, ref int second) { 
   return (first > second) ? first : second; 
} 
 
void main() {
   int a = 1; 
   int b = 2;  
   
   greater(a, b) += 10;   
   writefln("a: %s, b: %s", a, b);   
}

Когда вы скомпилируете и выполните эту программу, она возвратит следующий результат:

a: 1, b: 12

Auto-Функции

Auto-Функции могут возвращать значение любого типа. Нет никаких ограничений на возвращаемый тип. Ниже приведён простой пример функции типа auto.

import std.stdio;

auto add(int first, double second) { 
   double result = first + second; 
   return result; 
} 

void main() { 
   int a = 1; 
   double b = 2.5; 
   
   writeln("add(a,b) = ", add(a, b)); 
}

Когда вы скомпилируете и выполните эту программу, она возвратит следующий результат:

add(a,b) = 3.5

Функции с переменным числом аргументов

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

import std.stdio;
import core.vararg;

void printargs(int x, ...) {  
   for (int i = 0; i < _arguments.length; i++) {  
      write(_arguments[i]);  
   
      if (_arguments[i] == typeid(int)) { 
         int j = va_arg!(int)(_argptr); 
         writefln("\t%d", j); 
      } else if (_arguments[i] == typeid(long)) { 
         long j = va_arg!(long)(_argptr); 
         writefln("\t%d", j); 
      } else if (_arguments[i] == typeid(double)) { 
         double d = va_arg!(double)(_argptr); 
         writefln("\t%g", d); 
      } 
   } 
}
  
void main() { 
   printargs(1, 2, 3L, 4.5); 
}

Когда вы скомпилируете и выполните эту программу, она возвратит следующий результат:

int 2 
long 3 
double 4.5

Inout-Функции

Inout может использоваться как для параметров, так и для возвращаемых типов функций. Это похоже на шаблон для квалификаторов изменяемости, const и immutable. Атрибут изменяемости выводится из параметра. Значит, inout переносит выведенный атрибут изменяемости на возвращаемый тип. Ниже показан простой пример, показывающий, как меняется квалификатор изменяемости.

import std.stdio;

inout(char)[] qoutedWord(inout(char)[] phrase) { 
   return '"' ~ phrase ~ '"';
}

void main() { 
   char[] a = "проверка a".dup; 

   a = qoutedWord(a); 
   writeln(typeof(qoutedWord(a)).stringof," ", a);  

   const(char)[] b = "проверка b"; 
   b = qoutedWord(b); 
   writeln(typeof(qoutedWord(b)).stringof," ", b); 

   immutable(char)[] c = "проверка c"; 
   c = qoutedWord(c); 
   writeln(typeof(qoutedWord(c)).stringof," ", c); 
} 

Когда вы скомпилируете и выполните эту программу, она возвратит следующий результат:

char[] "проверка a"
const(char)[] "проверка b"
string "проверка c"

Функции-свойства

Свойства (properties) позволяют использовать функции-члены как данные-члены. Они используют ключевое слово @property. Свойства связаны с родственной функцией, возвращающей значение, когда оно требуется. Ниже приведен простой пример свойства.

import std.stdio;

// прямоугольник 
struct Rectangle { 
   double width; // ширина 
   double height; // высота 

   // площадь 
   double area() const @property {  
      return width*height;  
   } 

   void area(double newArea) @property {  
      auto multiplier = newArea / area; 
      width *= multiplier; 
      writeln("Значение установлено!");  
   } 
}

void main() { 
   auto rectangle = Rectangle(20,10); 
   writeln("Площадь равна ", rectangle.area);  
   
   rectangle.area = 300; 
   writeln("Изменённая ширина равна ", rectangle.width); 
}

Когда вы скомпилируете и выполните эту программу, она возвратит следующий результат:

Площадь равна 200
Значение установлено!
Изменённая ширина равна 30

Предыдущая страница
Следующая страница