Programowanie D - funkcje

W tym rozdziale opisano funkcje używane w programowaniu D.

Definicja funkcji w D

Podstawowa definicja funkcji składa się z nagłówka funkcji i treści funkcji.

Składnia

return_type function_name( parameter list ) { 
   body of the function 
}

Oto wszystkie części funkcji -

  • Return Type- Funkcja może zwrócić wartość. Plikreturn_typejest typem danych wartości zwracanej przez funkcję. Niektóre funkcje wykonują żądane operacje bez zwracania wartości. W tym przypadku return_type jest słowem kluczowymvoid.

  • Function Name- To jest rzeczywista nazwa funkcji. Nazwa funkcji i lista parametrów razem tworzą podpis funkcji.

  • Parameters- Parametr działa jak symbol zastępczy. Gdy funkcja jest wywoływana, przekazujesz wartość do parametru. Ta wartość jest określana jako rzeczywisty parametr lub argument. Lista parametrów odnosi się do typu, kolejności i liczby parametrów funkcji. Parametry są opcjonalne; to znaczy, funkcja może nie zawierać żadnych parametrów.

  • Function Body - Treść funkcji zawiera zbiór instrukcji, które definiują, co robi funkcja.

Wywołanie funkcji

Możesz wywołać funkcję w następujący sposób -

function_name(parameter_values)

Typy funkcji w D

Programowanie D obsługuje szeroki zakres funkcji i są one wymienione poniżej.

  • Czyste funkcje
  • Funkcje Nothrow
  • Funkcje ref
  • Funkcje automatyczne
  • Funkcje wariadyczne
  • Funkcje Inout
  • Funkcje właściwości

Różne funkcje opisano poniżej.

Czyste funkcje

Czyste funkcje to funkcje, które nie mogą uzyskać dostępu do globalnego lub statycznego, zmiennego stanu, poza swoimi argumentami. Może to umożliwić optymalizacje oparte na fakcie, że czysta funkcja gwarantuje, że nie zmutuje niczego, co nie zostanie do niej przekazane, aw przypadkach, gdy kompilator może zagwarantować, że czysta funkcja nie może zmienić swoich argumentów, może zapewnić pełną, funkcjonalną czystość, że jest gwarancją, że funkcja zawsze zwróci ten sam wynik dla tych samych argumentów).

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"); //cannot call impure function 'writeln'
   
   debug writeln("in foo()"); // ok, impure code allowed in debug statement 
   // x = i;  // error, modifying global state 
   // i = x;  // error, reading mutable global state 
   // i = *p; // error, reading const global state
   i = y;     // ok, reading immutable global state 
   auto myvar = new int;     // Can use the new expression: 
   return i; 
}

void main() { 
   writeln("Value returned from pure function : ",purefunc(x,null,null)); 
}

Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik -

Value returned from pure function : 30

Funkcje Nothrow

Funkcje Nothrow nie zgłaszają żadnych wyjątków pochodzących z klasy Exception. Funkcje nothrow są kowariantne z funkcjami rzucającymi.

Nothrow gwarantuje, że funkcja nie emituje żadnego wyjątku.

import std.stdio; 

int add(int a, int b) nothrow { 
   //writeln("adding"); This will fail because writeln may throw 
   int result; 
   
   try { 
      writeln("adding"); // compiles 
      result = a + b; 
   } catch (Exception error) { // catches all exceptions 
   }

   return result; 
} 
 
void main() { 
   writeln("Added value is ", add(10,20)); 
}

Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik -

adding 
Added value is 30

Funkcje ref

Funkcje ref pozwalają funkcjom zwracać się przez odniesienie. Jest to analogiczne do parametrów funkcji ref.

import std.stdio;

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);   
}

Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik -

a: 1, b: 12

Funkcje automatyczne

Funkcje automatyczne mogą zwracać wartość dowolnego typu. Nie ma ograniczeń dotyczących zwracanego typu. Prosty przykład funkcji auto typu jest podany poniżej.

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)); 
}

Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik -

add(a,b) = 3.5

Funkcje wariadyczne

Funkcje variadiac to te funkcje, w których liczba parametrów funkcji jest określana w czasie wykonywania. W C istnieje ograniczenie związane z posiadaniem co najmniej jednego parametru. Ale w programowaniu D nie ma takiego ograniczenia. Poniżej przedstawiono prosty przykład.

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); 
}

Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik -

int 2 
long 3 
double 4.5

Funkcje Inout

Inout może być używany zarówno dla parametrów, jak i typów zwracanych funkcji. Jest jak szablon dla zmiennych, stałych i niezmiennych. Atrybut zmienności jest wywnioskowany z parametru. Oznacza, że ​​inout przenosi wydedukowany atrybut zmienności do typu zwracanego. Poniżej przedstawiono prosty przykład pokazujący, jak zmienia się zmienność.

import std.stdio;

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

void main() { 
   char[] a = "test a".dup; 

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

   const(char)[] b = "test b"; 
   b = qoutedWord(b); 
   writeln(typeof(qoutedWord(b)).stringof," ", b); 

   immutable(char)[] c = "test c"; 
   c = qoutedWord(c); 
   writeln(typeof(qoutedWord(c)).stringof," ", c); 
}

Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik -

char[] "test a" 
const(char)[] "test b" 
string "test c"

Funkcje właściwości

Właściwości pozwalają na używanie funkcji składowych, takich jak zmienne składowe. Używa słowa kluczowego @property. Właściwości są połączone z pokrewną funkcją, która zwraca wartości na podstawie wymagań. Poniżej przedstawiono prosty przykład właściwości.

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("Value set!");  
   } 
}

void main() { 
   auto rectangle = Rectangle(20,10); 
   writeln("The area is ", rectangle.area);  
   
   rectangle.area(300); 
   writeln("Modified width is ", rectangle.width); 
}

Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik -

The area is 200 
Value set! 
Modified width is 30