Estructuras (structs)

Una forma de definir tipos de datos compuestos o personalizados en D es definirlos a través de una estructura mediante la palabra reservada struct.

struct Person {
    int age;
    int height;
    float ageXHeight;
}

Las structs son siempre construidas en la pila (stack, en inglés; a no ser que sean creadas mediante new) y son siempre copiadas por valor en asignaciones o como parámetros en llamadas a funciones.

auto p = Person(30, 180, 3.1415);
auto t = p; // copy

Cuando un nuevo objeto de tipo struct se crea, todos sus miembros pueden ser inicializados en el orden en que están definidos en dicha struct. Se puede definir un constructor predeterminado a través del método this(...). Si se necesita evitar conflictos con los nombres de los parámetros, la instancia actual de la estructura puede ser accedida mediante this.

struct Person {
    this(int age, int height) {
        this.age = age;
        this.height = height;
        this.ageXHeight = cast(float)age * height;
    }
        ...

Person p = Person(30, 180); // inicialización
p = Person(30, 180);  // asignación a una nueva instancia

Una struct puede contener cualquier número de funciones miembro. Estos métodos son públicos (public) de forma predeterminada y accesibles desde cualquier sitio. Estos métodos podrían declararse como privados (private) y sólo podría acceder a ellos otro método de la struct o código dentro del mismo módulo.

struct Person {
    void doStuff() {
        ...
    private void privateStuff() {
        ...

p.doStuff(); // llamada al método doStuff
p.privateStuff(); // prohibido

Funciones miembro constantes

Si una función miembro es declarada usando const, no está permitido que dicha función modifique ninguno de sus miembros. Esto lo fuerza el compilador. Hacer una función miembro const hace que sólo se pueda llamar desde cualquier objeto const o immutable; además se garantiza que los objetos que llaman a dicha función nunca cambiarán el estado del objeto.

Funciones miembro estáticas

Si una función miembro se declara como static, esta se podrá llamar sin la necesidad de instanciar ningún objeto (por ejemplo: Person.myStatic()), pero no está permitido acceder a miembros que no estén marcados como static. Esto se puede usar cuando un método no necesita acceder a ningún miembro del objeto pero que, evidentemente, pertenece a la misma clase. Además, esto se puede usar para proporcionar funcionalidad sin tener que crear una instancia. Por ejemplo, algunos patrones Singleton utilizan static para su implementación.

Herencia

Hay que tener en cuenta que una estructura no puede heredar de otras estructuras. Las herencias entre tipos sólo se pueden construir usando clases, que se verán en una sección futura. Sin embargo, mediante las sentencia alias this y/o mixins fácilmente se puede conseguir herencia polimórfica.

En profundidad

Ejercicio

Dada la estructura struct Vector3, implementa las siguientes funciones y haz que la aplicación de ejemplo se ejecute correctamente:

  • length(): devuelve la longitud del vector.
  • dot(Vector3): devuelve el producto de dos vectores.
  • toString(): devuelve una cadena representando este vector. La función std.string.format devuelve una cadena usando una sintaxis similar a la de printf: format("MyInt = %d", myInt). Las cadenas de caracteres (strings en inglés) serán explicadas con más detalles en próximas secciones.

rdmd playground.d