我正在寻找教堂通过引用的例子。 这个例子有效,但它似乎是糟糕的形式,因为我正在"返回"输入。 这会浪费内存吗? 有没有对类进行操作的显式方法?
class PowerPuffGirl {
var secretIngredients: [1..0] string;
}
var bubbles = new PowerPuffGirl();
bubbles.secretIngredients.push_back("sugar");
bubbles.secretIngredients.push_back("spice");
bubbles.secretIngredients.push_back("everything nice");
writeln(bubbles.secretIngredients);
proc kickAss(b: PowerPuffGirl) {
b.secretIngredients.push_back("Chemical X");
return b;
}
bubbles = kickAss(bubbles);
writeln(bubbles.secretIngredients);
它产生输出
sugar spice everything nice
sugar spice everything nice Chemical X
使用函数修改气泡的最有效方法是什么?
Chapel 是否通过引用传递参数可以通过参数意图来控制。例如,整数通常按值传递,但我们可以通过引用传递一个:
proc increment(ref x:int) { // 'ref' here is an argument intent
x += 1;
}
var x:int = 5;
increment(x);
writeln(x); // outputs 6
类型在未指定参数时传递的方式称为默认意向。默认情况下,Chapel 通过引用传递记录、域和数组;但是在这些数组中,只有数组可以在函数内部修改。(记录和域通过const ref
传递 - 这意味着它们是通过引用传递的,但它们传递给的函数无法修改它们。数组传递ref
或const ref
取决于函数对它们的处理 - 请参阅数组默认意图)。
现在,具体到您的问题,类实例默认按"值"传递,但 Chapel 认为类实例的"值"是一个指针。这意味着,与其允许字段(比如)被改变,不如通过ref
传递类实例,只是意味着它可以被不同的类实例替换。目前没有办法说类实例的字段不应该在函数中修改(除了使它们成为显式不可变的数据类型)。
鉴于所有这些,我认为您在问题中提供的代码示例没有任何效率低下的地方。特别是在这里:
proc kickAss(b: PowerPuffGirl) {
b.secretIngredients.push_back("Chemical X");
return b;
}
接受b
的参数将接收指向实例的指针的副本,return b
将返回该指针的副本。实例的内容(特别是secretIngredients
数组)将保留在原来的位置,并且不会在此过程中复制。
还有一件事:
这个例子有效,但它似乎是糟糕的形式,因为我正在"返回"输入。
正如我所说,这对于类实例或整数来说并不是真正的问题。数组呢?
proc identity(A) {
return A;
}
var A:[1..100] int;
writeln(identity(A));
在此示例中,identity()
中的return A
实际上会导致创建数组的副本。当数组传入identity()
时,该副本不是创建的,因为数组是带着const ref
意图传递的。但是,由于该函数返回作为引用的"按值"返回的内容,因此有必要将其作为返回的一部分进行复制。另请参阅语言演进文档中默认按值返回的数组。
在任何情况下,如果想要通过引用返回数组,可以使用ref
或const ref
返回意图来实现,例如:
proc refIdentity(ref arg) ref {
return arg;
}
var B:[1..10] int;
writeln(refIdentity(B));
现在没有数组的副本,一切都只是引用相同的B
.
请注意,目前可以编写程序来返回对不再存在的变量的引用。编译器在该区域包含一些检查,但它并不完整。希望该领域的改善很快到来。