如何使过程更改变量参数的值?

Jus*_*tin 5 delphi delphi-2010

我试图做一个简单的过程,从输入的字符串中删除空格:

procedure RemoveSpaces(StringParameter : String);
var
   SpacePosition: Integer;
begin
   SpacePosition := Pos(' ',StringParameter);
   while SpacePos <> 0 do
   begin
      Delete(StringParameter,SpacePos,1);
      SpacePosition := Pos(' ',StringParameter);
   end;
end;
Run Code Online (Sandbox Code Playgroud)

但在测试以下代码中的过程之后:

var
   Input : String;
begin
   Readln(Input);
   RemoveSpaces(Input);
   Writeln(Input);
   Readln;
end.
Run Code Online (Sandbox Code Playgroud)

很明显,输入变量只是从程序中反过来,好像它从未改变过一样.

我认为这可能仅限于我可以用我尚未实现的程序做什么但后来我记得我之前已经创建了一个带有StringList参数的过程,并按字母顺序对StringList中的字符串进行排序并保存更改到StringList变量参数:

var
   myStringList : TStringList;

implementation

procedure StringListSort(StringList : TStringList);
begin
   //Sort StringList
end;

procedure TFormName.ButtonNameClick(Sender: TObject);
begin
   StringListSort(myStringList);
end; 
Run Code Online (Sandbox Code Playgroud)

欢迎解决我的问题.

Dav*_*nan 12

procedure RemoveSpaces(StringParameter: string);
Run Code Online (Sandbox Code Playgroud)

您正在按值传递字符串参数.在语义上1,副本由您传递的参数组成,并且对该副本进行任何修改.呼叫者不会观察到修改.

您需要通过引用传递参数.当您通过引用传递时,该过程对原始变量进行操作,而不是副本.

在Pascal和Delphi中,您使用var关键字通过引用传递.更改

procedure RemoveSpaces(StringParameter: string);
Run Code Online (Sandbox Code Playgroud)

procedure RemoveSpaces(var StringParameter: string);
Run Code Online (Sandbox Code Playgroud)

您观察到与TStringList参数看起来不同的行为的原因是,TStringList这是一个引用类型的类.这意味着,给定List: TStringListList是对对象的引用.有关值和引用类型之间区别的更多讨论,请参阅我的答案:为什么我们应该使用类而不是记录,反之亦然?

文件中有这样一段对此事说:

类类型的变量实际上是引用对象的指针.因此,多个变量可以引用同一个对象.与其他指针一样,类类型变量可以保存该值nil.但是,您不必显式取消引用类型变量来访问它指向的对象.例如,SomeObject.Size := 100将值赋给引用的对象100Size属性SomeObject; 你不会写这个SomeObject^.Size := 100.

这里的文档更明确地说明类类型变量实际上只是指针.

您可以使用RTL函数更有效,更简单地实现您的过程StringReplace:

procedure RemoveSpaces(var StringParameter: string);
begin
  StringParameter := StringReplace(StringParameter, ' ', '', [rfReplaceAll]);
end;
Run Code Online (Sandbox Code Playgroud)

我还要评论一个函数可能是更好的选择.这使您可以灵活地传递除变量之外的其他内容,例如文字或常量.而且您还可以更轻松地编写和链接函数.

所以这就是

function SpacesRemoved(const str: string): string;
begin
  Result := StringReplace(str, ' ', '', [rfReplaceAll]);
end;
Run Code Online (Sandbox Code Playgroud)

然后不必写:

RemoveSpaces(Input);
Writeln(Input);
Run Code Online (Sandbox Code Playgroud)

你可以写

Writeln(SpacesRemoved(Input));
Run Code Online (Sandbox Code Playgroud)

1我在语义上说,因为a string是一个引用类型,虽然是一个特殊的类型.区别在于,如果多个变量引用相同的字符串对象,则在进行修改时,将字符串复制到新对象,并为修改变量赋予唯一引用.这称为写时复制,其作用是使string数据类型的行为类似于值类型.