Programmazione D - Funzioni

Questo capitolo descrive le funzioni utilizzate nella programmazione D.

Definizione di funzione in D

Una definizione di funzione di base consiste in un'intestazione di funzione e un corpo di funzione.

Sintassi

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

Ecco tutte le parti di una funzione:

  • Return Type- Una funzione può restituire un valore. Ilreturn_typeè il tipo di dati del valore restituito dalla funzione. Alcune funzioni eseguono le operazioni desiderate senza restituire un valore. In questo caso, return_type è la parola chiavevoid.

  • Function Name- Questo è il nome effettivo della funzione. Il nome della funzione e l'elenco dei parametri insieme costituiscono la firma della funzione.

  • Parameters- Un parametro è come un segnaposto. Quando viene richiamata una funzione, si passa un valore al parametro. Questo valore viene indicato come parametro o argomento effettivo. L'elenco dei parametri si riferisce al tipo, all'ordine e al numero dei parametri di una funzione. I parametri sono opzionali; ovvero, una funzione non può contenere parametri.

  • Function Body - Il corpo della funzione contiene una raccolta di istruzioni che definiscono cosa fa la funzione.

Chiamare una funzione

Puoi chiamare una funzione come segue:

function_name(parameter_values)

Tipi di funzione in D

La programmazione D supporta un'ampia gamma di funzioni e sono elencate di seguito.

  • Funzioni pure
  • Funzioni Nothrow
  • Funzioni di riferimento
  • Funzioni automatiche
  • Funzioni variadiche
  • Funzioni di Inout
  • Funzioni di proprietà

Di seguito vengono spiegate le varie funzioni.

Funzioni pure

Le funzioni pure sono funzioni che non possono accedere allo stato mutabile globale o statico, salvo tramite i loro argomenti. Questo può consentire ottimizzazioni basate sul fatto che una funzione pura è garantita per non mutare nulla che non le viene passato, e nei casi in cui il compilatore può garantire che una funzione pura non possa alterare i suoi argomenti, può abilitare la purezza completa, funzionale, che è la garanzia che la funzione restituirà sempre lo stesso risultato per gli stessi argomenti).

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

Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:

Value returned from pure function : 30

Funzioni Nothrow

Le funzioni Nothrow non generano eccezioni derivate dalla classe Exception. Le funzioni di Nothrow sono covarianti con quelle di lancio.

Nothrow garantisce che una funzione non generi alcuna eccezione.

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

Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:

adding 
Added value is 30

Funzioni di riferimento

Le funzioni Ref consentono alle funzioni di restituire per riferimento. Questo è analogo ai parametri della funzione 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);   
}

Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:

a: 1, b: 12

Funzioni automatiche

Le funzioni automatiche possono restituire valori di qualsiasi tipo. Non ci sono restrizioni sul tipo da restituire. Di seguito viene fornito un semplice esempio per la funzione di tipo automatico.

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

Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:

add(a,b) = 3.5

Funzioni variadiche

Le funzioni Variadiac sono quelle funzioni in cui il numero di parametri per una funzione è determinato in runtime. In C, c'è una limitazione di avere almeno un parametro. Ma nella programmazione D, non esiste tale limitazione. Di seguito viene mostrato un semplice esempio.

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

Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:

int 2 
long 3 
double 4.5

Funzioni di Inout

L'inout può essere utilizzato sia per i tipi di parametri che per quelli restituiti. È come un modello per mutable, const e immutable. L'attributo mutabilità è dedotto dal parametro. Significa che inout trasferisce l'attributo mutabilità dedotto al tipo restituito. Di seguito è mostrato un semplice esempio che mostra come la mutabilità viene modificata.

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

Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:

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

Funzioni di proprietà

Le proprietà consentono di utilizzare le funzioni membro come le variabili membro. Utilizza la parola chiave @property. Le proprietà sono collegate alla funzione correlata che restituisce valori in base al requisito. Di seguito è mostrato un semplice esempio di proprietà.

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

Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:

The area is 200 
Value set! 
Modified width is 30