Обобщения
Обобщения позволяют параметризовать тип на основе другого типа. Рассмотрим тип 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
Обобщения особенно полезны при реализации типов коллекций. Array, Hash, Set — обобщённые типы, как и Pointer.
Можно указать несколько параметров типа:
class MyDictionary(K, V)
end
Для параметров типа можно использовать любые имена:
class MyDictionary(KeyType, ValueType)
end
Выведение переменных типа
Ограничения типа в конструкторе обобщённого типа являются свободными переменными, если аргументы типа не указаны, после чего используются для их выведения. Например:
MyBox.new(1) # : MyBox(Int32)
MyBox.new("hello") # : MyBox(String)
В приведённом выше коде нам не пришлось указывать аргументы типа для MyBox: компилятор вывел их следующим образом:
-
MyBox.new(value)делегируетinitialize(@value : T) -
Tещё не привязана к типу, поэтому компилятор связывает её с типом переданного аргумента
Так с обобщёнными типами работать проще.
Обобщённые структуры и модули
Структуры и модули тоже могут быть обобщёнными. Обобщённый модуль подключается следующим образом:
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
Обратите внимание: в приведённом выше примере T становится Int32, поскольку Foo.new(1) превращает U в Int32, что, в свою очередь, превращает T в Int32 при подключении обобщённого модуля.
Наследование обобщённых типов
От обобщённых классов и структур можно наследоваться. При наследовании можно указать экземпляр обобщённого типа или делегировать переменные типа:
class Parent(T)
end
class Int32Child < Parent(Int32)
end
class GenericChild(T) < Parent(T)
end
To the extent possible under law, the persons who contributed to this workhave waived
all copyright and related or neighboring rights to this workby associating CC0 with it.
https://crystal-lang.org/reference/1.2/syntax_and_semantics/generics.html