Descargar

7. Clases y tipos propios

Clases

class Personaje {
    var nombre: text            // campo (con tipo)
    var vida: number = 10       // campo con valor inicial
    static var creados = 0      // compartido por todos los Personaje

    constructor(nombre: text) {
        this.nombre = nombre    // this. es opcional si no hay ambigüedad
        creados += 1
    }

    get vivo(): bool { return vida > 0 }            // propiedad calculada (se lee sin paréntesis)
    function recibir(n: number) { vida = max(0, vida - n) }
    function toString(): text { return "${nombre} (${vida})" }  // cómo se imprime
}

var ana = Personaje("Ana")
ana.recibir(4)
print(ana, ana.vivo, Personaje.creados)
▶ Probar en el editor
  • Los objetos se crean llamando a la clase como una función: Personaje("Ana").
  • toString() decide cómo se ve el objeto en print y en "${...}".

Propiedades con get y set

class Termometro {
    var celsius: number = 0
    get fahrenheit(): number { return celsius * 9 / 5 + 32 }
    set fahrenheit(f: number) { celsius = (f - 32) * 5 / 9 }
}
var t = Termometro()
t.fahrenheit = 212
print(t.celsius, t.fahrenheit)
▶ Probar en el editor

Miembros estáticos

class Id {
    static var siguiente = 1
    static function nuevo(): number {
        siguiente += 1
        return siguiente - 1
    }
}
print(Id.nuevo(), Id.nuevo())
▶ Probar en el editor

Visibilidad

private delante de un campo o método lo oculta fuera de la clase (y fuera del archivo para declaraciones globales).

Herencia

class Animal {
    var nombre: text
    constructor(nombre: text) { this.nombre = nombre }
    function sonido(): text { return "..." }
    function hablar(): text { return "${nombre} dice ${sonido()}" }
}

class Perro extends Animal {
    var raza: text = "mestizo"
    constructor(nombre: text, raza: text) {
        super(nombre)              // constructor de la clase base
        this.raza = raza
    }
    function sonido(): text { return "¡guau!" }  // reemplaza el método de Animal
    function hablar(): text { return super.hablar() + " (" + raza + ")" }
}

var p = Perro("Toby", "beagle")
print(p.hablar(), p is Animal, p is Perro)
▶ Probar en el editor

Structs

Un struct es una clase pensada para datos: tiene un constructor automático con sus campos en orden y se compara por valor.

struct Punto { var x: number = 0; var y: number = 0 }
var a = Punto(1, 2)
var b = Punto(1, 2)
print(a == b, a, Punto(y: 5))
▶ Probar en el editor

Interfaces

Una interfaz enumera los métodos que debe tener una clase. HyperEZ comprueba que la clase los implementa.

interface Dibujable {
    function dibujar(): text
}
class Cuadro implements Dibujable {
    function dibujar(): text { return "[]" }
}
var cosas: list = [Cuadro()]
foreach c in cosas { print(c.dibujar(), c is Dibujable) }
▶ Probar en el editor

Enums

enum Estado { Menu, Jugando, Pausa }
var e = Estado.Jugando
print(e, e.name, e.ordinal, Estado.count)

enum Dificultad { Facil = 1, Normal = 2, Dificil = 3 }   // valores propios (números o textos)
print(Dificultad.Dificil.value)

var mensaje = match e {
    Estado.Menu => "en el menú"
    Estado.Jugando => "jugando"
    else => "en pausa"
}
print(mensaje)
▶ Probar en el editor

Sobrecarga de operadores

Una clase (o un struct) puede definir qué hacen los operadores con sus objetos mediante métodos con estos nombres:

OperadorMétodo
a + b a - b a * b a / b a % b a ** badd(b) sub(b) mul(b) div(b) mod(b) pow(b)
n + a, n * a (número a la izquierda)add(n), mul(n) del objeto
< <= > >=compareTo(b): devuelve un número negativo, 0 o positivo
== !=equals(b)
a[i], a[i] = vget(i), set(i, v)
len(a)propiedad length
class Dinero {
    var centimos: number
    constructor(euros: number) { centimos = round(euros * 100) }
    function add(o: Dinero): Dinero { return Dinero((centimos + o.centimos) / 100) }
    function mul(n: number): Dinero { return Dinero(centimos * n / 100) }
    function compareTo(o: Dinero): number { return centimos - o.centimos }
    function equals(o: Dinero): bool { return centimos == o.centimos }
    function toString(): text { return (centimos / 100).toFixed(2) + " €" }
}
var precio = Dinero(2.5)
var total = precio * 3 + Dinero(1)
print(total, total > precio, Dinero(1) == Dinero(1))
▶ Probar en el editor

Las clases nativas usan el mismo mecanismo: por eso Matrix y Vec2 se suman con +.