delphi - 在方法链中用作输出和(非参考)输入的值
问题描述
考虑以下方法链接的最小示例,其中浮点变量out
由早期方法设置(使用参数),然后(使用const
参数)传递给链中的后续方法:
program ChainedConundrum;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils;
type
ValueType = Double;
TRec = record
function GetValue(out AOutput: ValueType): TRec;
procedure ShowValue(const AInput: ValueType);
end;
function TRec.GetValue(out AOutput: ValueType): TRec;
begin
AOutput := 394;
Result := Self;
end;
procedure TRec.ShowValue(const AInput: ValueType);
begin
Writeln(AInput);
end;
var
R: TRec;
Value: ValueType = 713;
begin
R.GetValue(Value).ShowValue(Value);
Readln;
end.
我最初希望这会打印浮点数394
(以某种格式),但它没有(必然);当我使用 Delphi 10.3.2 的 32 位编译器构建程序时,程序会打印713
. 使用调试器单步执行程序确认初始GetValue
值Value
被传递给ShowValue
。
但是,如果我使用 64 位编译器构建它,394
则会打印出来。同样,如果我ValueType
从更改Double
为Int32
,我会同时获得394
两个版本。Int64
产生394
64 位和713
32 位。字符串产生更新的值。类就像记录一样工作。然而,与实例方法相反,类方法总是给我更新的值。当然,放弃方法链 ( R.GetValue(Value); R.ShowValue(Value)
) 也是如此。
毫不奇怪,如果我将AInput
参数ShowValue
从const
(或未修饰的值)参数更改为var
参数,我总是会得到更新的值。
我的结论是
- 不允许在这样的方法链中同时设置和传递变量,或者
- 编译器中有一个错误。
我的问题是:它是什么?如果不允许,文档在哪里说明了这一点?到目前为止,我还没有找到相关的段落。(短语“序列点”似乎很少出现在 WWW 上的短语“Delphi”附近。)
解决方案
在这里或其他地方对此问题发表评论的每个人都同意这“感觉像”或“显然”是编译器错误。
我在 Embarcadero Jira 创建了问题RSP-29733。
转向可能的解决方法,请注意问题似乎是编译器使用了变量的旧值。因此,当值更改接近变量的使用时,就会出现问题。
但是,变量的地址没有改变,所以如果你通过引用而不是值传递变量,问题就消失了。一种方法是在第二次传递值时使用var
参数,即使您不需要,甚至在语义上也不需要。
因此,一种更自然的方法似乎是使用const [Ref]
参数:
procedure ShowValue(const [Ref] AInput: ValueType);
这与未修饰的参数具有相同的语义,const
但强制编译器通过引用传递变量,从而避免了错误。
推荐阅读
- javascript - 如何使用反应导航?
- javascript - 如何使用 CSS 创建可悬停的彩虹?
- c++ - 为什么只有指向函数的指针而不是函数的var?
- android - 未调用Android活动startActivityForResult
- c++ - 如何让while循环与数字生成器一起使用?
- c++ - 为什么我在尝试添加两个链接列表时遇到此错误?
- php - 如何修复 PHP 致命错误:调用未定义函数 is_ssl()
- javascript - Jquery .load 函数似乎将页面加载为独立页面
- google-chrome-devtools - 如何在开发人员工具中阻止特定文件中的代码?
- javascript - 如何将移动按钮控件添加到 html 画布