Programación D - Funciones

Este capítulo describe las funciones utilizadas en la programación D.

Definición de función en D

Una definición de función básica consta de un encabezado de función y un cuerpo de función.

Sintaxis

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

Aquí están todas las partes de una función:

  • Return Type- Una función puede devolver un valor. losreturn_typees el tipo de datos del valor que devuelve la función. Algunas funciones realizan las operaciones deseadas sin devolver un valor. En este caso, return_type es la palabra clavevoid.

  • Function Name- Este es el nombre real de la función. El nombre de la función y la lista de parámetros juntos constituyen la firma de la función.

  • Parameters- Un parámetro es como un marcador de posición. Cuando se invoca una función, se pasa un valor al parámetro. Este valor se conoce como parámetro o argumento real. La lista de parámetros se refiere al tipo, orden y número de parámetros de una función. Los parámetros son opcionales; es decir, una función puede no contener parámetros.

  • Function Body - El cuerpo de la función contiene una colección de declaraciones que definen lo que hace la función.

Llamar a una función

Puede llamar a una función de la siguiente manera:

function_name(parameter_values)

Tipos de funciones en D

La programación D admite una amplia gama de funciones y se enumeran a continuación.

  • Funciones puras
  • Funciones de Nothrow
  • Funciones de referencia
  • Funciones automáticas
  • Funciones variadas
  • Funciones de Inout
  • Funciones de propiedad

Las diversas funciones se explican a continuación.

Funciones puras

Las funciones puras son funciones que no pueden acceder al estado mutable global o estático salvo a través de sus argumentos. Esto puede habilitar optimizaciones basadas en el hecho de que se garantiza que una función pura no mutará nada que no se le pase, y en los casos en que el compilador puede garantizar que una función pura no puede alterar sus argumentos, puede habilitar la pureza funcional completa, que es decir, la garantía de que la función siempre devolverá el mismo resultado para los mismos argumentos).

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

Cuando se compila y ejecuta el código anterior, produce el siguiente resultado:

Value returned from pure function : 30

Funciones de Nothrow

Las funciones de Nothrow no arrojan ninguna excepción derivada de la clase Exception. Las funciones de Nothrow son covariantes con las de lanzar.

Nothrow garantiza que una función no emite ninguna excepción.

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

Cuando se compila y ejecuta el código anterior, produce el siguiente resultado:

adding 
Added value is 30

Funciones de referencia

Las funciones de referencia permiten que las funciones regresen por referencia. Esto es análogo a los parámetros de la función de referencia.

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

Cuando se compila y ejecuta el código anterior, produce el siguiente resultado:

a: 1, b: 12

Funciones automáticas

Las funciones automáticas pueden devolver valor de cualquier tipo. No hay restricciones sobre qué tipo se devolverá. A continuación se ofrece un ejemplo sencillo de la función de tipo automático.

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

Cuando se compila y ejecuta el código anterior, produce el siguiente resultado:

add(a,b) = 3.5

Funciones variadas

Las funciones Variadiac son aquellas funciones en las que el número de parámetros para una función se determina en tiempo de ejecución. En C, existe la limitación de tener al menos un parámetro. Pero en la programación D, no existe tal limitación. A continuación se muestra un ejemplo sencillo.

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

Cuando se compila y ejecuta el código anterior, produce el siguiente resultado:

int 2 
long 3 
double 4.5

Funciones de Inout

El inout se puede utilizar tanto para parámetros como para tipos de funciones de retorno. Es como una plantilla para mutable, constante e inmutable. El atributo de mutabilidad se deduce del parámetro. Significa que inout transfiere el atributo de mutabilidad deducido al tipo de retorno. A continuación se muestra un ejemplo sencillo que muestra cómo se cambia la mutabilidad.

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

Cuando se compila y ejecuta el código anterior, produce el siguiente resultado:

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

Funciones de propiedad

Las propiedades permiten usar funciones miembro como variables miembro. Utiliza la palabra clave @property. Las propiedades están vinculadas con una función relacionada que devuelve valores según los requisitos. A continuación se muestra un ejemplo sencillo de propiedad.

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

Cuando se compila y ejecuta el código anterior, produce el siguiente resultado:

The area is 200 
Value set! 
Modified width is 30