Programmation D - Fonctions

Ce chapitre décrit les fonctions utilisées dans la programmation D.

Définition de fonction en D

Une définition de fonction de base se compose d'un en-tête de fonction et d'un corps de fonction.

Syntaxe

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

Voici toutes les parties d'une fonction -

  • Return Type- Une fonction peut renvoyer une valeur. lereturn_typeest le type de données de la valeur renvoyée par la fonction. Certaines fonctions exécutent les opérations souhaitées sans renvoyer de valeur. Dans ce cas, le return_type est le mot-clévoid.

  • Function Name- Il s'agit du nom réel de la fonction. Le nom de la fonction et la liste des paramètres constituent ensemble la signature de la fonction.

  • Parameters- Un paramètre est comme un espace réservé. Lorsqu'une fonction est appelée, vous transmettez une valeur au paramètre. Cette valeur est appelée paramètre ou argument réel. La liste des paramètres fait référence au type, à l'ordre et au nombre des paramètres d'une fonction. Les paramètres sont facultatifs; autrement dit, une fonction peut ne contenir aucun paramètre.

  • Function Body - Le corps de la fonction contient une collection d'instructions qui définissent ce que fait la fonction.

Appeler une fonction

Vous pouvez appeler une fonction comme suit -

function_name(parameter_values)

Types de fonction en D

La programmation D prend en charge un large éventail de fonctions et elles sont répertoriées ci-dessous.

  • Fonctions pures
  • Fonctions Nothrow
  • Fonctions de référence
  • Fonctions automatiques
  • Fonctions variadiques
  • Fonctions Inout
  • Fonctions de propriété

Les différentes fonctions sont expliquées ci-dessous.

Fonctions pures

Les fonctions pures sont des fonctions qui ne peuvent pas accéder à l'état global ou statique, mutable sauf via leurs arguments. Cela peut permettre des optimisations basées sur le fait qu'une fonction pure est garantie de ne muter rien qui ne lui est pas passé, et dans les cas où le compilateur peut garantir qu'une fonction pure ne peut pas modifier ses arguments, il peut activer une pureté fonctionnelle complète, qui est, la garantie que la fonction retournera toujours le même résultat pour les mêmes arguments).

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

Lorsque le code ci-dessus est compilé et exécuté, il produit le résultat suivant -

Value returned from pure function : 30

Fonctions Nothrow

Les fonctions Nothrow ne lèvent aucune exception dérivée de la classe Exception. Les fonctions de Nothrow sont covariantes avec celles de lancement.

Nothrow garantit qu'une fonction n'émet aucune exception.

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

Lorsque le code ci-dessus est compilé et exécuté, il produit le résultat suivant -

adding 
Added value is 30

Fonctions de référence

Les fonctions Ref permettent aux fonctions de revenir par référence. Ceci est analogue aux paramètres de la fonction 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);   
}

Lorsque le code ci-dessus est compilé et exécuté, il produit le résultat suivant -

a: 1, b: 12

Fonctions automatiques

Les fonctions automatiques peuvent renvoyer des valeurs de n'importe quel type. Il n'y a aucune restriction sur le type à renvoyer. Un exemple simple de fonction de type automatique est donné ci-dessous.

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

Lorsque le code ci-dessus est compilé et exécuté, il produit le résultat suivant -

add(a,b) = 3.5

Fonctions variadiques

Les fonctions Variadiac sont les fonctions dans lesquelles le nombre de paramètres d'une fonction est déterminé lors de l'exécution. En C, il y a une limitation d'avoir au moins un paramètre. Mais en programmation D, il n'y a pas de telle limitation. Un exemple simple est présenté ci-dessous.

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

Lorsque le code ci-dessus est compilé et exécuté, il produit le résultat suivant -

int 2 
long 3 
double 4.5

Fonctions Inout

L'inout peut être utilisé à la fois pour les paramètres et les types de retour de fonctions. C'est comme un modèle pour mutable, const et immuable. L'attribut de mutabilité est déduit du paramètre. Cela signifie que inout transfère l'attribut de mutabilité déduite au type de retour. Un exemple simple montrant comment la mutabilité est modifiée est présenté ci-dessous.

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

Lorsque le code ci-dessus est compilé et exécuté, il produit le résultat suivant -

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

Fonctions de propriété

Les propriétés permettent d'utiliser des fonctions membres comme des variables membres. Il utilise le mot clé @property. Les propriétés sont liées à une fonction associée qui renvoie des valeurs basées sur les exigences. Un exemple simple de propriété est présenté ci-dessous.

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

Lorsque le code ci-dessus est compilé et exécuté, il produit le résultat suivant -

The area is 200 
Value set! 
Modified width is 30