Во-первых, почти нет необходимости выполнять трюк class
+ ^parameterize
+ role
. Он появляется в некоторых внутренних компонентах, потому что помогает справиться с некоторыми проблемами начальной загрузки (это забавно, когда вы определяете язык в терминах самого себя). Тем не менее, в обычном коде Raku, просто напишите параметр c role
вместо class
. С точки зрения потребителя обычно нет никакой разницы; можно:
- Позвонить на него
.new
, чтобы создать экземпляр (который фактически создает за кулисами класс, известный как "каламбур" и создает экземпляр этого) - На самом деле, вызовите любой метод объекта типа с тем же результатом;
new
не является особенным - Наследуется от него (опять же, он работает на автоматически создаваемый класс)
С дополнительным бонусом, что кто-то может также составить его вместо наследования.
Во-вторых, нет никакой связи между class
, определенным внутри role
, и включающим role
(это общий принцип: вложение одного пакета в другой не подразумевает каких-либо отношений между их на уровне объектной модели). Таким образом, нам нужно сделать это отдельно generi c и создать его экземпляр.
Эти два заставляют нас:
role BinarySearchTree[::T] {
my role BinaryNode[::T] is rw {
has T $.item;
has BinaryNode $.left;
has BinaryNode $.right;
}
method create-node( T $x ) {
BinaryNode[T].new(item => $x)
}
}
my $bst = BinarySearchTree[Int].new;
$bst.create-node(6);
Что на самом деле должно работать, но компилятор похоже, неправильно выбрано время на BinaryNode[T]
. Мы можем обойти это, просто заставив его отложить параметризацию до времени выполнения; есть много способов сделать это, но написание BinaryNode[$(T)]
компактно и дешево (оптимизируется практически без дополнительных затрат). Таким образом, давая рабочий раствор:
role BinarySearchTree[::T] {
my role BinaryNode[::T] is rw {
has T $.item;
has BinaryNode $.left;
has BinaryNode $.right;
}
method create-node( T $x ) {
BinaryNode[$(T)].new(item => $x)
}
}
my $bst = BinarySearchTree[Int].new;
$bst.create-node(6);