我一直在阅读有关将参数传递给过程和函数的各种方法,但我仍然对 var
和 constref
的语义感到困惑。因为它们适用于记录(这是关于该语言的 Free Pascal 方言 v3.x)。
我的理解是:
var
和constref
都强制参数通过引用传递var
表明参数的突变是可能的,而const[ref]
则不然
这种区别对于数字和字符串等简单类型很有意义,但是对于结构化类型呢?假设我有以下记录:
A = record
x: Integer;
end;
以及一个作用于 A
的过程,如下所示:
procedure proc(var rec: A);
begin
rec.x := 42;
end;
即proc
确实没有重新分配rec
,但它确实会产生副作用,因为它会改变其形式化的字段范围。我能够在 fpc 3.0.4
下使用 var
或 constref
很好地编译它,但我的直觉是 rec
或许应该在这里声明为 var
,以表明该记录实例占用的内存被过程调用改变了?
换句话说,每当我不重新分配形式参数并且我想强制通过引用传递记录时,或者仅当该记录也真正不可变时,我是否应该使用 constref该过程也不写入其任何字段?而且,从编译器的角度来看,差异是什么,因为显然它没有捕获这样一个事实:即使使用 constref,我也能够改变记录的字段,是通过引用传递的吗?
更新:
正如响应者所指出的,上述示例代码应该(并且确实)无法使用fpc
3.x 进行编译;我过于简单化了。就我而言,A
记录保存对动态数组的引用,而我能够通过 constref
参数重新分配这些数组元素,这让我感到困惑:
A = record
x: Array of Integer;
end;
procedure proc(constref rec: A);
begin
rec.x[0] := 42; // this works
end;
听起来原因是动态数组本质上只是一个指针,而arr[i]
是取消引用该指针的语法糖。
最佳答案
您链接到的文档解释了 constref
与 const
的不同之处仅在于 constref
参数始终通过引用传递,而 >const
参数可以通过编译器确定的引用或值传递。
所以,这段代码
procedure proc(constref rec: A);
begin
rec.x := 42;
end;
应该会导致编译错误。当我尝试在https://godbolt.org/可用的fpc版本中编译它时(2.6.0、2.6.2、2.6.4、3.0.2、3.0.4 和 3.2.0)编译器在所有情况下都将其视为无效而拒绝。
如果此代码在您安装的 fpc 3.0.4 中编译,则这是应该报告的编译器错误。然而,这似乎与我的观察结果不一致,因此我建议您仔细重新检查您的发现。
关于pascal - 通过记录: constref vs var,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64258332/