代码之家  ›  专栏  ›  技术社区  ›  Brian Dolan

如何保存可接受类型的列表以便在教堂进行比较

  •  5
  • Brian Dolan  · 技术社区  · 7 年前

    假设我有课 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 回复  |  直到 7 年前
        1
  •  4
  •   Brad    7 年前

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

    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
    

    因此,要测试 好学生 ExcellentStudent ,你可以写:

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

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

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

    因为两者都有 好学生 优秀学生 对于此条件将返回true。

    作为一个重要的注意事项,将这个条件简单地写为:

    if student.type == GoodStudent
    

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

    proc accept(student: Student) { ... }
    

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

    proc accept(student) { ... }
    

    但如果你允许其他人- 学生 要传入的类型。

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

    var acceptableStudentTypes: [1..2] = [GoodStudent, ExcellentStudent];
    

    相反,创建一个tuple类型来存储要与之比较的所有类型:

    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 从类作用域(逻辑上的,在您拥有它的地方)到模块作用域的声明。这是因为教堂里有一只明显的虫子 filed an issue against .

    或者,如果你能 优秀学生 的子类 好学生 ,我想下面的内容要好多了( 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!                   
    
        2
  •  3
  •   saruftw    7 年前

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