Как сохранить список приемлемых типов для сравнения в часовне - PullRequest
0 голосов
/ 23 мая 2018

Предположим, у меня есть класс Student, BadStudent:Student, GoodStudent:Student и ExcellentStudent: Student.Я хочу, чтобы метод класса работал только с Good и Exceptional студентами.Что-то вроде:

class AdvancedBasketWeaving {

  // this is the question:
  var acceptableStudentTypes: [1..2] = [GoodStudent, ExcellentStudent];

  proc accept(student: Student) {
    for at in this.acceptableStudentTypes {
      if student.type == at then return "YES!";
    }
    return "Computer says 'No'";
  }
}

Как мне получить эту функциональность?

Ответы [ 2 ]

0 голосов
/ 23 мая 2018

Есть два инструмента, которые я думаю, вы захотите использовать для этого шаблона:

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!                   
0 голосов
/ 23 мая 2018

Вы можете попытаться сохранить типы, приведя их к типу string.

Например,

var a = [int: string, string: string];
writeln(a);
var b = 1;
var c = "sdasas";
if b.type: string == a[1] then writeln("This matches!");
if c.type: string != a[1] then writeln("This doesn't match!");
...