gpt4 book ai didi

delphi - 变量应该在调用函数之前初始化吗?

转载 作者:行者123 更新时间:2023-12-03 14:39:36 25 4
gpt4 key购买 nike

当我调用函数来获取值时,我通常会初始化变量,以防函数失败或不返回任何内容,并且我想避免处理未初始化的变量。我对字符串、整数或任何其他类型执行相同的操作。

整数变量示例:

vPropValue := 0;
vPropValue := GetPropValue(vObject,'Height');

IF vPropValue > 0 Then
...

这是我最常见的使用方式。

我知道我可以使用:

If GetPropValue(vObject,'Height') > 0 Then
...

但在第一个示例中,如果我稍后在代码中再次需要结果,我会避免多次调用函数。

字符串也是如此(尽管我知道本地字符串被初始化为空字符串,而整数不能容纳任何值)

vName := '';
vName := GetObjectName(vObject,'ObjectName');

IF Trim(vPropStrValue) <> '' Then
...

我知道我可以采取措施避免重复赋值,例如确保 Function 在一切失败时返回 0。但我有数百个函数,我不能相信我从来没有犯过函数如何处理所有事情的错误,而且我确信如果一切失败,有些函数不会返回 0。

我试图理解为什么这不是可取的做法以及如何最好地避免它。

编辑

下面是函数未返回正确值或 0 的示例:

function GetValue(vType:integer):integer;
begin
if vType=1 then
Result:=100
else if (vType>2) and (vType<=9) then
Result:=200;

end;

procedure TForm1.Button1Click(Sender: TObject);
var vValue:integer;
begin

vValue:=GetValue(11);
Button1.Caption:=IntToStr(vValue);

end;

在这种情况下,从函数返回的值是一些随机数。

在这种情况下,初始化似乎是有效的方法。 还是不?

编辑2:

正如大卫在回答中指出的那样,正确,有一个警告

[dcc32 Warning] Unit1.pas(33): W1035 Return value of function 'GetValue' might be undefined

但是,我无缘无故地忽略了它,只是没有看那里。因为它让我编译它,所以我认为还可以。因此,我确实查找了警告,并“修复”了相当多具有类似问题的函数,因为所有 IF 结果可能尚未定义。

编辑 3 和结论:

我希望它能扩大问题和解释的范围:

也许我在大多数函数中使用的另一个扭曲的例子也可以解释为什么我认为需要初始化变量,那就是我不确定我的函数是否始终能够正确运行,特别是在这种情况下的嵌套函数。其中大部分仍然是这样设置的:

function GetProperty(vType:integer):integer;
begin
Try
if vType = 99 then
Result:=GetDifferentProperty(vType)// <-- Call to another Function, that could return whatever...
else
begin
if vType=1 then
Result:=100
else if (vType>2) and (vType<=9) then
Result:=200;
end;
except
end;
end;

现在我正在解决这些Try except End;,但有些函数已经有 10 年历史了,根据我当时的经验,期望它们 100% 工作是不可靠的。

作为该项目的唯一开发人员,我认为我应该信任我的功能(以及我的其余代码),但我无法想象在多个开发人员环境中所有功能都已正确设置。

所以我的结论:由于我没有照顾基础知识 - 正确设计的函数,我需要进行所有这些检查(变量初始化,Try except行..)以及可能还有其他一些不必要的东西。

最佳答案

假设vPropValue是一个局部变量,那么这段代码

vPropValue := 0;
vPropValue := GetPropValue(vObject,'Height');

没有区别
vPropValue := GetPropValue(vObject,'Height');

一个更简单的例子可能是这样的:

i := 0;
i := 1;

0分配给i然后立即将1分配给i有什么意义?所以,你肯定不会这么写。你可以写:

i := 1;

在您的代码中,在此答案的顶部,您为同一个变量分配了两次。第一个赋值中分配的值将立即替换为第二个赋值中分配的值。因此,第一个分配毫无意义,应该删除。

第二个示例稍微复杂一些。假设您的函数编写正确,并且始终分配给它们的返回值,并且 vName 是局部变量,那么

vName := '';
vName := GetObjectName(vObject,'ObjectName');

没有区别
vName := GetObjectName(vObject,'ObjectName');

我添加额外条件的原因与函数返回值的实现的怪癖有关,如下所述。这种情况与上面的情况的区别在于返回值类型。这里它是一个托管类型,string,而在第一个示例中,该类型是一个简单的Integer

同样,考虑到函数总是分配给返回值的附加条件,第一次分配是毫无意义的,因为该值会立即被替换。删除第一个作业。

<小时/>

对于您编辑中的函数,如果您启用提示和警告,编译器将警告您其错误的实现。编译器会告诉您并非所有代码路径都会返回值。

function GetValue(vType:integer):integer;
begin
if vType=1 then
Result:=100
else if (vType>2) and (vType<=9) then
Result:=200;
end;

如果两个条件都不满足,则不会为结果变量分配任何值。这个函数应该是:

function GetValue(vType:integer):integer;
begin
if vType=1 then
Result:=100
else if (vType>2) and (vType<=9) then
Result:=200
else
Result:=0;
end;

我无法强调始终从函数返回值有多么重要。事实上,Delphi 甚至允许你的函数被编译,这是一个可怕的弱点。

<小时/>

双重赋值有时对您有用的原因是 Delphi 中函数返回值实现的一个怪癖。与几乎所有其他语言不同,某些更复杂类型的 Delphi 函数返回值实际上是一个 var 参数。所以这个函数

function foo: string;

实际上,在语义上,与此相同:

procedure foo(var result: string);

这是德尔福设计师做出的一个非常奇怪的决定。在大多数其他语言中,如 C、C++、C#、Java 等,函数返回值就像从被调用者传递到调用者的按值参数。

这意味着,如果您愿意,您可以通过函数的返回值将值传递给函数。例如,考虑以下代码:

// Note: this code is an example of very bad practice, do not write code like this

function foo: string;
begin
Writeln(Result);
end;

procedure main;
var
s: string;
begin
s := 'bar';
s := foo;
end;

当你调用main时,它会输出bar。这是一个相当奇怪的实现细节。你不应该依赖它。让我重复一遍。你不应该依赖它。不要养成在调用站点初始化返回值的习惯。这会导致代码无法维护。

而是遵循简单的规则,确保函数返回值始终由函数分配,并且在分配之前绝不读取。

<小时/>

有关函数返回值实现的更多详细信息由 documentation 提供。 ,我强调的是:

The following conventions are used for returning function result values.

  • Ordinal results are returned, when possible, in a CPU register. Bytes are returned in AL, words are returned in AX, and double-words are returned in EAX.
  • Real results are returned in the floating-point coprocessor's top-of-stack register (ST(0)). For function results of type Currency, the value in ST(0) is scaled by 10000. For example, the Currency value 1.234 is returned in ST(0) as 12340.
  • For a string, dynamic array, method pointer, or variant result, the effects are the same as if the function result were declared as an additional var parameter following the declared parameters. In other words, the caller passes an additional 32-bit pointer that points to a variable in which to return the function result.
  • Int64 is returned in EDX:EAX.
  • Pointer, class, class-reference, and procedure-pointer results are returned in EAX.
  • For static-array, record, and set results, if the value occupies one byte it is returned in AL; if the value occupies two bytes it is returned in AX; and if the value occupies four bytes it is returned in EAX. Otherwise, the result is returned in an additional var parameter that is passed to the function after the declared parameters.

关于delphi - 变量应该在调用函数之前初始化吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33927750/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com