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

时间:2018-05-23 00:31:30

标签: chapel

假设我有课程StudentBadStudent:StudentGoodStudent: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'";
  }
}

如何获得此功能?

2 个答案:

答案 0 :(得分:4)

我认为您有两种工具可用于此模式:

1)第一个是Chapel的演员(:)。对于类,转换类似于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

因此,要测试GoodStudentExcellentStudent,您可以写:

if (student:GoodStudent != nil || student:ExcellentStudent != nil) then
  return "YES!";

或者,如果每个ExcellentStudent也是GoodStudent,您可以考虑在类层次结构中将其作为GoodStudent的子类,而不是它的兄弟。在这种情况下,您可以简单地将条件写为:

if student:GoodStudent != nil then return "YES!";

因为GoodStudentExcellentStudent都会为此条件返回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);

这导致了我建议的解决方案(try it online):

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中有一个明显的错误,我filed an issue against

或者,如果您可以将ExcellentStudent作为GoodStudent的子类,我认为以下内容更为出色(try it online):

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!                   

答案 1 :(得分:3)

您可以尝试通过将类型转换为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!");