Delphi - 如何使用可选的VAR参数调用过程?

5

Delphi 2010 - 我有一个处理字符串的例程。它有三种不同的处理方式,我可能需要任意组合,包括所有三种处理方式。我正在尝试确定如何调用我的例程,但是我尝试的每一种方法都会导致问题。我想要做的是像这样调用过程...

StringProcess(StartString1, VarProcess1, VarProcess2, VarProcess3);

但实际上,这可能只是我只想要其中两个进程。
StringProcess(StartString1, '', VarProcess2, VarProcess3);

过程定义类似于

procedure StringProcess(StartString: string; var S1:String; var S2:string; var S3:string);

总结一下,我该如何定义我的过程来返回1到3个VAR变量?Delphi希望我总是传递3个变量,如果我不需要它,我只需忽略其中一个。是否有一种方法可以传递“不存在”的VAR参数,并根据需要忽略它们?
谢谢

@lurker 那个问题可能会提供一个很好的替代方案,但它绝对不是重复的。 - GolezTrol
1
这个问题涉及到一个有3个var字符串输入的函数,询问如何使其中一个变成可选项。另一个问题是关于一个array of const输入,询问如何将其变成一个var参数。对我来说听起来有些不同。 - GolezTrol
@GolezTrol 对不起,我可能引用了错误的SO答案。我使用的引用问题的标题是如何创建一个接受可变数量的可变参数的函数。我已经撤回了我的关闭投票。 - lurker
3个回答

11

var 参数不能是可选的,它必须传递一个变量。如果您需要的是可选参数,可以使用指针代替:

procedure StringProcess(StartString: string; S1:PString; S2:Pstring; S3:Pstring);
begin
  ...
  if S1 <> nil then
  begin
    // Use S1^ as needed...
  end;
  ...
end;

然后你可以做这样的事情:

StringProcess(StartString1, @VarProcess1, @VarProcess2, @VarProcess3);
StringProcess(StartString1, nil, @VarProcess2, @VarProcess3);
StringProcess(StartString1, nil, nil, @VarProcess3);
StringProcess(StartString1, @VarProcess1, nil, @VarProcess3);
...

指针的东西看起来不太好,但至少这个解决方案允许您检测调用者是否实际传递了一个字符串或nil,因此您可以检查是否需要处理该字符串。 - GolezTrol
1
另一种方式也是可能的,StringProcess(StartString1, PString(nil)^, VarProcess2, .. 然后在过程中测试 @S1<>nil。过程的声明保持不变,但看起来并不美观... - Sertac Akyuz

9
问题在于,你的 StringProcess 程序必须具有表示 S1、S2 和 S3 的变量,以便在修改这些值时使用。毫无疑问,你不想为不感兴趣的值声明变量而经历头疼的过程。
考虑的一个选项是将所有变量捆绑到记录结构中,如下所示:
type
  TStringData = record
    S1, S2, S3: string;
  end;

procedure StringProcess(StartString: string; var StringData: TStringData);

但我认为你可以更进一步。我怀疑你在StringProcess例程中并没有真正使用S1、S2和S3的输入,这意味着它们可以作为输出参数。如果是这样,我建议你写成:

function StringProcess(StartString: string): TStringData;

同样简单,但在这种情况下仍然没有视图可以选择要使用的字符串。这意味着所有字符串都由过程计算,这可能会浪费循环(取决于处理的复杂性)。 - GolezTrol
1
如果有意使用输入值来决定应计算什么,那么if (S1 = '')if (StringData.S1 = '')可以被解释为完全相同的方式。由于字符串是托管类型,而本地记录变量将自动初始化为所有空字符串。 - Disillusioned

1

var参数不能是可选的。解决方法是为函数定义重载:

procedure StringProcess(StartString: string; var S1:String); overload;
procedure StringProcess(StartString: string; var S1:String; var S2:string); overload;
procedure StringProcess(StartString: string; var S1:String; var S2:string; var S3:string); overload;

您可以这样实现重载:

procedure StringProcess(StartString: string; var S1:String); overload;
var
  S2, S3: String;
begin
  StringProcess(StartString, S1, S2, S3);
end;

当使用一个进程的重载时,只需调用具有大多数进程的重载并使用虚拟变量来捕获输出。


这样是行不通的,因为如果我传递两个字符串,程序就不知道我是在传递S1和S3,还是S2和S3等等...它只知道我正在传递2个字符串。我必须添加另一个参数,告诉过程我想要7种组合中的哪一种。 - user1009073
好的,我现在明白你的意思了。快速解决方法是只传递3个变量和一个位掩码,告诉函数你实际想要哪些变量。但为了更好的解决方案,我会选择完全不同的方法,因为这种方法根本不灵活。将不同类型的处理隔离在不同的类中或其他方式。无论如何,答案的核心是:你不能有可选的var参数,所以你必须绕过它。 - GolezTrol
@David - 当我尝试将''作为参数传递时,我收到一个错误,告诉我不能将CONST用作VAR变量。这很有道理,但是否有一种方法告诉编译器,如果没有输入变量,则不要返回任何变量? - user1009073
2
我认为一个类会是这个问题的理想解决方案。将输入字符串设置在类中,并创建函数或属性获取器以获取不同的处理字符串。每个函数都可以检查处理的共享部分是否已经完成。如果没有,它可以调用执行该部分的方法,并将结果存储在类字段中。 - GolezTrol
2
@GolezTrol 同意。人们经常害怕创建小类。但这很可能是一个单一职责类的理想示例。 - Disillusioned
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接