D Programmierung - Funktionen

Dieses Kapitel beschreibt die Funktionen der D-Programmierung.

Funktionsdefinition in D.

Eine grundlegende Funktionsdefinition besteht aus einem Funktionsheader und einem Funktionskörper.

Syntax

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

Hier sind alle Teile einer Funktion -

  • Return Type- Eine Funktion kann einen Wert zurückgeben. Dasreturn_typeist der Datentyp des Werts, den die Funktion zurückgibt. Einige Funktionen führen die gewünschten Operationen aus, ohne einen Wert zurückzugeben. In diesem Fall ist der return_type das Schlüsselwortvoid.

  • Function Name- Dies ist der tatsächliche Name der Funktion. Der Funktionsname und die Parameterliste bilden zusammen die Funktionssignatur.

  • Parameters- Ein Parameter ist wie ein Platzhalter. Wenn eine Funktion aufgerufen wird, übergeben Sie einen Wert an den Parameter. Dieser Wert wird als tatsächlicher Parameter oder Argument bezeichnet. Die Parameterliste bezieht sich auf den Typ, die Reihenfolge und die Anzahl der Parameter einer Funktion. Parameter sind optional; Das heißt, eine Funktion darf keine Parameter enthalten.

  • Function Body - Der Funktionskörper enthält eine Sammlung von Anweisungen, die definieren, was die Funktion tut.

Eine Funktion aufrufen

Sie können eine Funktion wie folgt aufrufen:

function_name(parameter_values)

Funktionstypen in D.

Die D-Programmierung unterstützt eine Vielzahl von Funktionen, die im Folgenden aufgeführt sind.

  • Reine Funktionen
  • Nothrow-Funktionen
  • Ref Funktionen
  • Automatische Funktionen
  • Variadische Funktionen
  • Inout-Funktionen
  • Eigenschaftsfunktionen

Die verschiedenen Funktionen werden nachfolgend erläutert.

Reine Funktionen

Reine Funktionen sind Funktionen, die nicht über ihre Argumente auf globale oder statische, veränderbare Zustände zugreifen können. Dies kann Optimierungen ermöglichen, die auf der Tatsache beruhen, dass eine reine Funktion garantiert nichts mutiert, was nicht an sie übergeben wird, und in Fällen, in denen der Compiler garantieren kann, dass eine reine Funktion ihre Argumente nicht ändern kann, kann dies die volle funktionale Reinheit ermöglichen ist die Garantie, dass die Funktion immer das gleiche Ergebnis für die gleichen Argumente zurückgibt).

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

Wenn der obige Code kompiliert und ausgeführt wird, ergibt sich das folgende Ergebnis:

Value returned from pure function : 30

Nothrow-Funktionen

Nothrow-Funktionen lösen keine Ausnahmen aus, die von der Klasse Exception abgeleitet sind. Nothrow-Funktionen sind kovariant mit Wurffunktionen.

Nothrow garantiert, dass eine Funktion keine Ausnahme ausgibt.

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

Wenn der obige Code kompiliert und ausgeführt wird, ergibt sich das folgende Ergebnis:

adding 
Added value is 30

Ref Funktionen

Mit Ref-Funktionen können Funktionen als Referenz zurückgegeben werden. Dies ist analog zu den Funktionsparametern 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);   
}

Wenn der obige Code kompiliert und ausgeführt wird, ergibt sich das folgende Ergebnis:

a: 1, b: 12

Automatische Funktionen

Auto-Funktionen können Werte beliebigen Typs zurückgeben. Es gibt keine Einschränkung, welcher Typ zurückgegeben werden soll. Ein einfaches Beispiel für die automatische Typfunktion ist unten angegeben.

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

Wenn der obige Code kompiliert und ausgeführt wird, ergibt sich das folgende Ergebnis:

add(a,b) = 3.5

Variadische Funktionen

Variadiac-Funktionen sind solche Funktionen, bei denen die Anzahl der Parameter für eine Funktion zur Laufzeit bestimmt wird. In C gibt es eine Einschränkung, mindestens einen Parameter zu haben. Bei der D-Programmierung gibt es jedoch keine solche Einschränkung. Ein einfaches Beispiel ist unten gezeigt.

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

Wenn der obige Code kompiliert und ausgeführt wird, ergibt sich das folgende Ergebnis:

int 2 
long 3 
double 4.5

Inout-Funktionen

Das Inout kann sowohl für Parameter- als auch für Rückgabetypen von Funktionen verwendet werden. Es ist wie eine Vorlage für veränderlich, konstant und unveränderlich. Das Veränderbarkeitsattribut wird aus dem Parameter abgeleitet. Das heißt, inout überträgt das abgeleitete Mutabilitätsattribut an den Rückgabetyp. Ein einfaches Beispiel, das zeigt, wie sich die Veränderlichkeit ändert, ist unten dargestellt.

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

Wenn der obige Code kompiliert und ausgeführt wird, ergibt sich das folgende Ergebnis:

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

Eigenschaftsfunktionen

Eigenschaften ermöglichen die Verwendung von Elementfunktionen wie Elementvariablen. Es verwendet das Schlüsselwort @property. Die Eigenschaften sind mit verwandten Funktionen verknüpft, die je nach Anforderung Werte zurückgeben. Ein einfaches Beispiel für eine Eigenschaft ist unten gezeigt.

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

Wenn der obige Code kompiliert und ausgeführt wird, ergibt sich das folgende Ergebnis:

The area is 200 
Value set! 
Modified width is 30