我想尝试一下Chapel中的类和多态性,所以我试图 得到以下示例代码以工作:
module SomeAnimals {
class Animal {
}
class Bird: Animal {
}
class Fish: Animal {
}
proc Bird.fly() {
writeln("Flying ...!");
}
proc Fish.swim() {
writeln("Swimming ...!");
}
} // module SomeAnimals
proc main() {
use SomeAnimals;
var anim: Animal;
anim = new Fish();
select (anim.type) {
when Fish do anim.swim();
}
delete anim;
anim = new Bird();
select (anim.type) {
when Bird do anim.fly();
}
delete anim;
} // proc main
这可以编译,但是在运行时,它只是退出而没有产生任何 打印。显然,由于某些原因,未执行对select语句中包含的anim.swim()和anim.fly()方法的调用。如果不使用这些select语句检查多态变量“ anim”的实际类型,则代码当然不会编译。
上面的示例实际上是对作品的直译 利用Fortran的“选择类型”语句的Fortran 2008代码。是否 Chapel提供了类似的陈述,还是必须以完全不同的方式编码此示例才能在Chapel中工作?我在教堂文档中找不到任何相关内容。
答案 0 :(得分:5)
理解代码为什么不起作用的关键是Chapel中的myVar.type
是指变量的 static 类型,而不是其 dynamic 类型。因此,即使您和我看到anim
最初是Fish
,之后是Bird
,但anim.type
始终是Animal
,因为它被声明为{ {1}}为其指定静态类型var anim: Animal;
。您可以通过将main()函数更改为以下(try it online)来看到此内容:
Animal
输出将是:
proc main() {
use SomeAnimals;
var anim: Animal;
anim = new Fish();
writeln(anim.type:string);
anim = new Bird();
writeln(anim.type:string);
} // proc main
在Chapel中推断类变量的动态类型的一种方法是对其应用强制转换运算符(Animal
Animal
),其行为类似于C ++中的动态强制转换。也就是说,如果我尝试将静态类型为:
的变量强制转换为Animal
,但实际上是一个Fish
,我将得到Bird
的返回,表明该类对象既不是nil
也不是Fish
的子类。
因此,对您的main()进行重写,使其表现为您想要的(try it online):
Fish
(我使用的是proc main() {
use SomeAnimals;
var anim: Animal = new Fish();
var aFish = anim:Fish;
if aFish then
aFish.swim();
delete anim;
anim = new Bird();
var aBird = anim:Bird;
if aBird then
aBird.fly();
delete anim;
} // proc main
的简写if classVar ...
)
回到您的具体问题,关于Chapel是否具有类似于Fortran的类型select语句,但目前没有。为了对静态类型进行推理(例如if classVar != nil ...
与int
与real
与my record R
),像您一样对变量类型使用select语句是完全合理的(或者您可以提供函数的重载,我们将根据参数的静态类型选择正确的函数)。但是,对于在类层次结构中工作并且必须推理对象的动态类型的情况,您的主要工具将是如上所述的强制转换或动态调度,或者在类中存储显式字段以区分对象之间的动态类型。案例(可以将其视为动态投射的手动实现)。