Есть два инструмента, которые я думаю, вы захотите использовать для этого шаблона:
1) Первый - оператор приведения Чапеля (:
).Для классов приведение похоже на динамическое приведение C ++.Короче говоря, если объект класса подобен следующему экземпляру GoodStudent
:
var brian = new GoodStudent();
приведение объекта к типу класса вернет nil
, если объект не является подклассом этого класса иссылка на класс, если это так.Таким образом:
...(brian: Student != nil)... // will evaluate to true
...(brian: BadStudent != nil)... // will evaluate to false
...(brian: GoodStudent != nil)... // will evaluate to true
...(brian: ExcellentStudent != nil)... // will evaluate to false
Таким образом, чтобы проверить GoodStudent
или ExcellentStudent
, вы можете написать:
if (student:GoodStudent != nil || student:ExcellentStudent != nil) then
return "YES!";
В качестве альтернативы, если каждый ExcellentStudent
также является GoodStudent
, вы можете рассмотреть вопрос о том, чтобы сделать его подклассом GoodStudent
в иерархии классов, а не родственным ему.В этом случае вы могли бы просто написать условное выражение в виде:
if student:GoodStudent != nil then return "YES!";
, так как GoodStudent
и ExcellentStudent
вернули бы значение true для этого условного выражения.
В качестве важного примечания оно можетсоблазнительно просто написать это условие как:
if student.type == GoodStudent
, но это не даст правильного поведения в контексте вашей процедуры, поскольку оно объявлено следующим образом:
proc accept(student: Student) { ... }
В частности,запрос .type
вернет статический (во время компиляции) тип объекта класса, и в контексте этой подпрограммы статический тип student
равен Student
из-за его формального типа.Таким образом, сравнение его статического типа никогда не будет соответствовать GoodStudent
, даже если динамический тип объекта равен GoodStudent
.Использование динамического приведения устраняет это путем перехода от статического теста к динамическому.Другой подход состоит в том, чтобы сделать процедуру accept()
полностью универсальной, как показано ниже:
proc accept(student) { ... }
, но затем вы открываете шлюзы, позволяя передавать другие типы, не Student
.
2) Второе, что вам нужно (и основное внимание в вашем вопросе), - это тип кортежей, который, вероятно, является наилучшим / самым легким способом создания коллекции типов.Chapel поддерживает только массивы значений, а не типы, поэтому следующая строка в вашем коде недопустима:
var acceptableStudentTypes: [1..2] = [GoodStudent, ExcellentStudent];
Вместо этого создайте тип кортежа для хранения всех типов, с которыми вы хотите сравнить:
type acceptableStudentTypes = (GoodStudent, ExcellentStudent);
Это приводит к моему предложенному решению ( попробуйте его в Интернете ):
class Student {
}
class BadStudent: Student {
}
class GoodStudent: Student {
}
class ExcellentStudent: Student {
}
// a tuple of acceptable types
type acceptableStudentTypes = (GoodStudent, ExcellentStudent);
class AdvancedBasketWeaving {
proc accept(student: Student) {
// iterate over the tuple's size
for param i in 1..acceptableStudentTypes.size do
// see if dynamically casting the student to the type "works"
if student: acceptableStudentTypes(i) != nil then
return "YES!";
return "Computer says 'No'";
}
}
var course = new AdvancedBasketWeaving();
writeln(course.accept(new Student())); // Computer says 'No'
writeln(course.accept(new BadStudent())); // Computer says 'No'
writeln(course.accept(new GoodStudent())); // YES!
writeln(course.accept(new ExcellentStudent())); // YES!
Обратите внимание, что я переместил объявление acceptableStudentTypes
из области видимости класса (которыйлогично и где у вас это было) в объеме модуля.Это из-за явной ошибки в Chapel, из-за которой я подал проблему против .
Или, если вы можете сделать ExcellentStudent
подклассом GoodStudent
, я думаю следующеегораздо приятнее ( попробуйте онлайн ):
class Student {
}
class BadStudent: Student {
}
class GoodStudent: Student {
}
class ExcellentStudent: GoodStudent {
}
class AdvancedBasketWeaving {
proc accept(student: Student) {
if student: GoodStudent != nil then
return "YES!";
return "Computer says 'No'";
}
}
var course = new AdvancedBasketWeaving();
writeln(course.accept(new Student())); // Computer says 'No'
writeln(course.accept(new BadStudent())); // Computer says 'No'
writeln(course.accept(new GoodStudent())); // YES!
writeln(course.accept(new ExcellentStudent())); // YES!