传递记录:constref vs var

Passing records: constref vs var

我一直在阅读有关将参数传递给过程和函数的各种方法,但我仍然对 varconstref 应用于记录的语义感到困惑(这是关于该语言的 Free Pascal 方言,v3.x)。

我的理解是:

  1. varconstref 都强制参数通过引用传递
  2. 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 下用 varconstref 编译它,但我的直觉是 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] 是取消引用该指针的语法糖。

您 link 所查看的文档解释说 constrefconst 的不同之处仅在于 constref 参数始终通过引用传递,而 const参数可以通过引用或值传递,由编译器决定。

所以,这段代码

procedure proc(constref rec: A);
begin
  rec.x := 42;
end;

应该会导致编译错误。当我尝试在 https://godbolt.org/(2.6.0、2.6.2、2.6.4、3.0.2、3.0.4 和 3.2.0)可用的​​ fpc 版本中编译它时,编译器将其拒绝为无效所有案例。

如果此代码在您安装的 fpc 3.0.4 中编译,那么这是一个应该报告的编译器错误。然而,这似乎与我观察到的不一致,所以我建议您仔细 re-check 您的发现。