Génériques
Les génériques permettent de paramétrer un type basé sur un autre type. Considérons un type Box:
class MyBox(T)
def initialize(@value : T)
end
def value
@value
end
end
int_box = MyBox(Int32).new(1)
int_box.value # => 1 (Int32)
string_box = MyBox(String).new("hello")
string_box.value # => "hello" (String)
another_box = MyBox(String).new(1) # Error, Int32 doesn't match String
Les Génériques sont particulièrement utiles pour implémenter des types de collection. Array
, Hash
, Set
sont des types génériques. Pointer
également.
Plus d'un argument de type est permis:
class MyDictionary(K, V)
end
Seules des noms d'un unique caractère sont autorisés comme noms d'arguments de type.
Inférence de variables de type
Les restrictions de type dans un constructeur de type générique sont des variables libres quand les arguments de type ne sont pas spécifiés, et sont ensuite utilisés pour l'inférence. Par exemple:
MyBox.new(1) # : MyBox(Int32)
MyBox.new("hello") # : MyBox(String)
Dans le code précédent nous n'avons pas spécifié les arguments de type de MyBox
,
le compilateur les a déduits d'après la logique suivante:
MyBox.new(value)
délégue àinitialize(@value : T)
,T
n'existe pas, il est donc utilisé comme variable libre,- Parce-que
MyBox
est en faitMyBox(T)
, etT
est à la fois une variable libre et un argument de type,T
devient le type de la valeur passée en paramètre.
De cette manière il est moins laborieux de travailler avec les génériques.
Structs et modules génériques
Structs et modules peuvent être génériques également. Quand un module est générique vous l'incluez de cette manière:
module Moo(T)
def t
T
end
end
class Foo(U)
include Moo(U)
def initialize(@value : U)
end
end
foo = Foo.new(1)
foo.t # Int32
Notez que dans l'exmple précédent T
devient Int32
car Foo.new(1)
transforme U
en Int32
, qui à son tour transforme T
en Int32
via l'inclusion du module générique.
Héritage de types génériques
Les classes et structs génériques peuvent être hérités. Lors de l'héritage vous pouvez spécifier une instance du type générique, ou déléguer les variables de type:
class Parent(T)
end
class Int32Child < Parent(Int32)
end
class GenericChild(T) < Parent(T)
end