This is almost the same as the accepted answer but with some added dialogue (I had with Rob Napier, his other answers and Matt, Oliver, David from Slack) and links.
See the comments in
this discussion. The gist of it is:
+
is heavily overloaded (Apple seems to have fixed this for some cases)
The
+
operator is heavily overloaded. As of now, it has 27 different functions. So, if you are concatenating 4 strings, i.e., you have 3
+
operators, the compiler has to
check between 27 operators each time. That's 27^3 times. But that's not it.
还有一个检查,用于检查+
函数的lhs
和rhs
是否都有效,如果是,则调用核心append
。在那里,您可以看到可能会发生许多有点密集的检查。如果字符串存储为非连续的,那么似乎是实际上桥接到NSString的情况。然后,Swift必须将所有字节数组缓冲区重新组装成单个连续缓冲区,并需要沿途创建新缓冲区。然后,最终获得包含要尝试连接在一起的字符串的一个缓冲区。
简而言之,编译器检查分为3个集群,会减慢速度,即
必须考虑每个子表达式在可能返回的情况下的影响。因此,使用插值串联字符串,例如使用
" My fullName is \(firstName) \(LastName)"
,比使用
"My firstName is" + firstName + LastName
更好,因为插值
没有重载。
Swift 3已经做了
一些改进。有关更多信息,请阅读
如何合并多个数组而不减慢编译器速度?。尽管
+
运算符仍然被重载,但对于较长的字符串最好使用字符串插值。
可选项的使用(持续问题 - 可用解决方案)
在这个非常简单的项目中:
import UIKit
class ViewController: UIViewController {
let p = Person()
let p2 = Person2()
func concatenatedOptionals() -> String {
return (p2.firstName ?? "") + "" + (p2.lastName ?? "") + (p2.status ?? "")
}
func interpolationOptionals() -> String {
return "\(p2.firstName ?? "") \(p2.lastName ?? "")\(p2.status ?? "")"
}
func concatenatedNonOptionals() -> String {
return (p.firstName) + "" + (p.lastName) + (p.status)
}
func interpolatedNonOptionals() -> String {
return "\(p.firstName) \(p.lastName)\(p.status)"
}
}
struct Person {
var firstName = "Swift"
var lastName = "Honey"
var status = "Married"
}
struct Person2 {
var firstName: String? = "Swift"
var lastName: String? = "Honey"
var status: String? = "Married"
}
函数的编译时间如下:
21664.28ms /Users/Honey/Documents/Learning/Foundational/CompileTime/CompileTime/ViewController.swift:16:10 instance method concatenatedOptionals()
2.31ms /Users/Honey/Documents/Learning/Foundational/CompileTime/CompileTime/ViewController.swift:20:10 instance method interpolationOptionals()
0.96ms /Users/Honey/Documents/Learning/Foundational/CompileTime/CompileTime/ViewController.swift:24:10 instance method concatenatedNonOptionals()
0.82ms /Users/Honey/Documents/Learning/Foundational/CompileTime/CompileTime/ViewController.swift:28:10 instance method interpolatedNonOptionals()
请注意,
concatenatedOptionals
的编译时间非常长。可以通过以下方式解决:
let emptyString: String = ""
func concatenatedOptionals() -> String {
return (p2.firstName ?? emptyString) + emptyString + (p2.lastName ?? emptyString) + (p2.status ?? emptyString)
}
编译时间为88毫秒
问题的根本原因是编译器不能将""
识别为String
类型,实际上它是ExpressibleByStringLiteral
。
编译器会看到??
并且必须遍历所有符合该协议的类型,直到找到一个可以成为String
默认值的类型。
通过使用硬编码为String
的emptyString
,编译器不再需要遍历所有符合ExpressibleByStringLiteral
的类型。
要了解如何记录编译时间,请参见此处或此处。
以下是 Rob Napier 在 SO 上提供的其他类似答案:
为什么字符串相加需要很长时间才能构建?
如何合并多个数组而不会减慢编译器速度?
Swift 数组包含函数使构建时间变长
var statement = "create table if not exists \(self.tableName()) (\(columns))"
?它用于创建一个表,如果该表不存在的话。 - efischency+
手动进行字符串拼接更好。 - mattt