如何在Chapel中保留可接受类型的列表以进行比较

Bri*_*lan 5 chapel

假设我有类Student,BadStudent:Student,GoodStudent:StudentExcellentStudent: Student.我想要一个只能GoodExceptional学生一起操作的课程方法.就像是:

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'";
  }
}
Run Code Online (Sandbox Code Playgroud)

我如何获得此功能?

Bra*_*rad 4

我认为您需要使用两种工具来实现此模式:

1) 第一个是 Chapel 的强制转换运算符 ( :)。对于类,强制转换类似于 C++ 的动态强制转换。简而言之,给定一个类似以下实例的类对象GoodStudent

var brian = new GoodStudent();
Run Code Online (Sandbox Code Playgroud)

如果该对象不是该类的子类,则将返回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
Run Code Online (Sandbox Code Playgroud)

因此,要测试 aGoodStudent或 an ExcellentStudent,您可以编写:

if (student:GoodStudent != nil || student:ExcellentStudent != nil) then
  return "YES!";
Run Code Online (Sandbox Code Playgroud)

或者,如果 everyExcellentStudent也是 a GoodStudent,您可以考虑将其设为类层次结构中的子类GoodStudent,而不是其同级类。在这种情况下,您可以简单地将条件写为:

if student:GoodStudent != nil then return "YES!";
Run Code Online (Sandbox Code Playgroud)

因为对于这个条件,GoodStudentand都会返回 true。ExcellentStudent

重要的是,您可能会很想简单地将这个条件写为:

if student.type == GoodStudent
Run Code Online (Sandbox Code Playgroud)

但这不会在您的过程上下文中给出正确的行为,因为它声明如下:

proc accept(student: Student) { ... }
Run Code Online (Sandbox Code Playgroud)

具体来说,.type查询将返回类对象的静态(编译时)类型,并且在此例程的上下文中, 的静态类型student归因Student于其形式类型。GoodStudent因此,即使对象的动态类型是 ,比较其静态类型也永远不会匹配GoodStudent。使用动态转换通过从静态测试更改为动态测试来解决此问题。另一种方法是使该accept()过程完全通用,如下所示:

proc accept(student) { ... }
Run Code Online (Sandbox Code Playgroud)

Student但随后你通过允许其他非类型传入来打开闸门。

2)您需要的第二件事(也是您问题的焦点)是元组类型,这可能是创建类型集合的最佳/最轻量级方法。Chapel 仅支持值数组,而不支持类型,因此代码中的以下行不合法:

var acceptableStudentTypes: [1..2] = [GoodStudent, ExcellentStudent];
Run Code Online (Sandbox Code Playgroud)

相反,创建一个元组类型来存储要比较的所有类型:

type acceptableStudentTypes = (GoodStudent, ExcellentStudent);
Run Code Online (Sandbox Code Playgroud)

这导致了我建议的解决方案(在线尝试):

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!                   
Run Code Online (Sandbox Code Playgroud)

请注意,我已将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!                   
Run Code Online (Sandbox Code Playgroud)