pascal - 通过记录: constref vs var

标签 pascal freepascal

我一直在阅读有关将参数传递给过程和函数的各种方法,但我仍然对 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]是取消引用该指针的语法糖。

最佳答案

您链接到的文档解释了 constrefconst 的不同之处仅在于 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/

相关文章:

delphi - 与平台无关的方法来检查 Writeln to Output 是否可以安全使用?

c - Pascal 到 C 的翻译

c++ - 来自 C++ DLL 的 Free Pascal 回调

delphi - 如何在 Mac 上的 Lazarus 中执行与 shellexecute() 等效的操作?

delphi - RAD Studio 源代码标记/可视化的解释

multithreading - 如何从另一个线程中断 ReadLn

delphi - 在非 GUI 环境 (DLL) 中使用事件监听器 (Delphi)

delphi - 如何禁用控制台快速编辑模式

delphi - `this` 在delphi中等效的关键字

delphi - 有谁有一个关于如何使用 Synapse 的 Heartbeat 功能的好例子吗?