这是我的代码:
class
效果很好并且打印(如预期的那样)2.7183。但是,如果我在actor
定义中将Eapproximator
替换为Error:
/src/main/main.pony:18:34: receiver type is not a subtype of target type
var e_val = e_approx.evaluate()
^
Info:
/src/main/main.pony:18:17: receiver type: Eapproximator tag
var e_val = e_approx.evaluate()
^
/src/main/main.pony:6:3: target type: Eapproximator box
fun evaluate() :F64 =>
^
/src/main/main.pony:3:3: Eapproximator tag is not a subtype of Eapproxim
ator box: tag is not a subcap of box
new create(step' :F64) =>
^
Error:
/src/main/main.pony:19:19: cannot infer type of e_val
env.out.print(e_val.string())
,我会收到一堆错误:
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
我该怎么做才能解决这个问题?
答案 0 :(得分:4)
演员是Pony中的并发单位。这意味着同一程序中的许多不同角色可以同时运行,包括您的Main
和Eapproximator
角色。现在如果一个演员的领域被多个演员同时修改会发生什么?由于并行程序在现代硬件上的工作方式,你最有可能最终得到一些垃圾值。这称为数据竞争,它是并发编程中许多错误的来源。 Pony的目标之一是在编译时检测数据竞争,并且此错误消息是编译器告诉您正在尝试执行的操作可能不安全。
让我们来看看那条错误信息。
接收器类型不是目标类型的子类型
接收器类型是被调用对象的类型,e_approx
。目标类型是方法内this
的类型,Eapproximator.evaluate
。子类型意味着可以使用子类型的对象,就好像它是超类型的对象一样。因此,该部分告诉您evaluate
由于类型不匹配而无法在e_approx
上调用。
接收器类型:Eapproximator标签
e_approx
是Eapproximator tag
。无法读取或写入tag
对象。我会在一分钟内详细说明e_approx
为tag
的原因。
目标类型:Eapproximator框
this
内的 evaluate
是Eapproximator box
。可以读取box
对象,但不能写入。 this
为box
,因为evaluate
被声明为fun evaluate
,隐含地表示fun box evaluate
(这意味着默认情况下,方法无法修改其接收方。)
Eapproximator标签不是Eapproxim的子类型 ator box:tag不是box的子主题
根据此错误消息,tag
对象不是box
对象的子类型,这意味着tag
不能像{{1}一样使用}}。如果我们查看box
和tag
允许的内容,这是合乎逻辑的。 box
允许的内容多于box
:tag
无法读取tag
。如果类型允许的内容少于(或同样多)超类型,则类型只能是另一种类型的子类型。
那么为什么用class
替换actor
会使对象tag
成为对象?这与我之前谈到的数据竞争问题有关。演员对自己的领域有自由统治权。它可以从它们读取并写入它们。由于参与者可以同时运行,因此必须拒绝他们访问彼此的字段,以避免与字段所有者进行数据竞争。类型系统中有一些东西正是这样做的:tag
。演员只能将其他演员视为tag
,因为读取或写入演员是不安全的。它可以对那些tag
引用做的主要用处是发送异步消息(通过调用be
方法或行为),因为它既不是读也不是写。
当然,既然你的程序中没有Eapproximator
的任何变异,你的具体情况就是安全的。但是,除了尝试允许每个安全程序之外,尝试禁止每个不安全的程序要容易得多。
总结一下,除了将Eapproximator
作为一个类保留之外,您的程序并没有真正的修复。没有任何东西需要成为Pony计划中的演员。 actor是并发的单位,但这意味着它也是顺序的单位。需要顺序和同步的计算必须存在于单个actor中。然后,您可以将这些计算细分为各种类,以实现良好的代码卫生。