16

在适用于 iOS 平台的 Delphi XE4 中,引入了一种新的字符串类型:基于零的不可变字符串。到目前为止,Delphi 已经在写入可变字符串时进行了复制。所以问题是,这对我未来的编程意味着什么?一种字符串类型比另一种有什么优势吗?切换到新的字符串类型时我需要注意哪些陷阱(除了明显的 0 对 1 基数)?

4

1 回答 1

17

根据Marco Cantù 的白皮书stringXE4 iOS 目标中的数据类型实际上并不是一成不变的,尽管他似乎自相矛盾。

他说:

在新的基于 Delphi LLVM 的编译器中,有一种字符串类型,表示 Unicode 字符串 (UTF16),并映射到 Delphi XE3 中的当前字符串类型(Windows 编译器上 UnicodeString 类型的别名)。但是,这种新的字符串类型使用了不同的内存管理模型。字符串类型仍然是引用计数的,但它是不可变的,这意味着一旦构造了字符串内容,您就无法修改它。

但他接着说:

换句话说,字符串现在是基于 Unicode 的,即将成为不可变的,并且是引用计数的

并且:

然而,事情开始发生变化的地方是当您修改现有字符串时,不是通过用新值替换它(在这种情况下,您会得到一个全新的字符串),而是当您修改其中一个元素时,如以下行所示代码(以及在上一节中,我介绍了该主题):

Str1 [3] := 'x';

所有 Delphi 编译器都使用写时复制语义:如果您修改的字符串有多个引用,则首先复制它(根据需要调整所涉及的各种字符串的引用计数),然后再进行修改。

新编译器的功能与经典编译器非常相似。它实现了写时复制机制,除非有一个对字符串的引用,在这种情况下,字符串会被原地修改。例如,考虑以下代码,它输出实际字符串的内存位置。

然后他展示了一张带有变异字符串的 iOS 设备的图片。

官方文档中,我们有:

字符串是不可变的(常量),因此您不能将字符串作为数组索引并操作字符串中的字符。如果您尝试修改字符串,Delphi 移动编译器可能会发出消息 W1068 将来可能不支持就地修改字符串 (Delphi)。您可以指定消息 x1068 是作为警告还是错误发出。在提示和警告页面中,将警告“就地修改字符串...”设置为“真”或“错误”。

所以我将所有这些解释为 iOS 编译器的 XE4 版本仍然具有可变字符串。开发人员真的不希望您再改变字符串,并告诉您字符串在移动编译器上是不可变的。但它们似乎仍然是可变的。去搞清楚!


但是,您已收到通知,在未来的版本中,该字符串可能会变为不可变。

您现在可以通过设置为将来的版本做准备

{$WARN IMMUTABLE_STRINGS WARN}

这将使您了解更改的影响。如果您想系好安全带并停止改变字符串,您可以这样做:

{$WARN IMMUTABLE_STRINGS ERROR}

完成此操作后,您需要转换访问单个字符串元素的代码。我怀疑你会对这样的代码如此之少感到惊讶。我刚刚编译了 600,000 行代码,只看到了 120 个警告实例。其中大部分都在第三方单位。我看到这种变化引起了轰动,但老实说,我不相信很多代码会改变字符串。在绝大多数情况下,字符串是通过连接或调用函数(如Format. 该代码不受此影响。

我不认为有什么大的陷阱。您可以使用{$WARN IMMUTABLE_STRINGS ...}让编译器引导您完成整个过程。任何改变字符串的代码都应该转换为 use TStringBuilder

至于不可变的好处,我参考你为什么 .NET 字符串是不可变的?

如果您使用的是传统的 Windows 或 OSX 编译器,那么我认为没有令人信服的理由进行更改。iOS 编译器是全新的。对不可变字符串的更改已经浮动,但它可能永远不会发生。它可能只发生在移动编译器上,而不会发生在传统编译器上。现在,我会坐稳,等着看结果如何。

于 2013-04-25T10:48:00.883 回答