我尝试创建一个简单的过程,从输入的字符串中删除空格:
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;
但在测试以下代码中的过程后:
var
Input : String;
begin
Readln(Input);
RemoveSpaces(Input);
Writeln(Input);
Readln;
end.
很明显,输入变量只是从程序中反过来,好像它从未改变过一样。
我认为这可能仅限于我可以用我尚未实现的过程做什么但后来我记得我之前已经创建了一个带有StringList参数的过程,并按字母顺序对StringList中的字符串进行排序将更改保存到StringList变量参数:
var
myStringList : TStringList;
implementation
procedure StringListSort(StringList : TStringList);
begin
//Sort StringList
end;
procedure TFormName.ButtonNameClick(Sender: TObject);
begin
StringListSort(myStringList);
end;
欢迎解决我的问题。
答案 0 :(得分:12)
procedure RemoveSpaces(StringParameter: string);
您正在传递字符串参数按值。在语义上 1 ,副本由您传递的参数组成,并且对该副本进行任何修改。来电者没有观察到修改。
您需要通过参考传递参数。当您通过引用传递时,该过程对原始变量进行操作,而不是副本。
在Pascal和Delphi中,you pass by reference by using the var
keyword。变化
procedure RemoveSpaces(StringParameter: string);
到
procedure RemoveSpaces(var StringParameter: string);
您观察到TStringList
参数似乎有不同行为的原因是TStringList
是一个引用类型的类。这意味着给定List: TStringList
然后List
是对象的引用。有关值和引用类型之间区别的更多讨论,请参阅我的答案:Why should we use classes rather than records, or vice versa?
documentation可以就此事说:
类类型的变量实际上是引用对象的指针。因此,多个变量可以引用同一个对象。与其他指针一样,类类型变量可以保存值
nil
。但是,您不必显式取消引用类型变量来访问它指向的对象。例如,SomeObject.Size := 100
将值100
分配给Size
引用的对象的SomeObject
属性;你不会把它写成SomeObject^.Size := 100
。
这里的文档更明确地说明类类型变量实际上只是指针。
您可以使用RTL函数StringReplace
:
procedure RemoveSpaces(var StringParameter: string);
begin
StringParameter := StringReplace(StringParameter, ' ', '', [rfReplaceAll]);
end;
我还要评论一个函数可能是更好的选择。这使您可以灵活地传递除变量之外的其他内容,例如文字或常量。而且您还可以更轻松地编写和链接函数。
所以这将是
function SpacesRemoved(const str: string): string;
begin
Result := StringReplace(str, ' ', '', [rfReplaceAll]);
end;
然后不必写:
RemoveSpaces(Input);
Writeln(Input);
你可以写
Writeln(SpacesRemoved(Input));
1 我在语义上说,因为string
是一个引用类型,虽然是一个特殊的类型。区别在于,如果多个变量引用相同的字符串对象,则在进行修改时,将字符串复制到新对象,并为修改变量赋予唯一引用。这称为写时复制,其作用是使string
数据类型的行为类似于值类型。