字符串插值和字符串连接之间的区别
Difference between String interpolation and String concatenation
在具体处理非可选的 String
值时,字符串插值和字符串连接之间的区别是什么?
struct MyModel {
let value1: String
let value2: String
var displayNameByConcatenation: String {
return value1 + "-" + value2
}
var displayNameByInterpolation: String {
return "\(value1)-\(value2)"
}
}
- 是否会出现
displayNameByConcatenation
和 displayNameByInterpolation
不同的情况?喜欢长 unicode 字符串吗?
- 是否有可能以某种方式覆盖运算符
+
的行为或插值的行为以使它们在上面的示例中有所不同?
- 一个 faster/slower 比另一个好吗?
请注意,从 我们了解到字符串插值将使用 CustomStringConvertible 的 description
。但是 String
连接(运算符 +
)是否也调用 description
?
字符串插值:
- 减少打字
- 内部调用字符串
- 在 运行 时间内更快
一个缺点:
- 分隔你的字符串
插值和拼接各有优缺点
需要使用与预定义字符串的连接以获得更好的性能
"Concatenation allows you to combine to strings together and it only works on two strings."
更新。不确定 Swift 的早期版本允许什么,但目前您可以在同一语句中将 2 个以上的字符串连接在一起:
设 str = "Hi, my name is "
var concat = str + "2" + "3" + "4" + "5" + "works" //显示 "Hi, my name is 2345 works"
因为+的两个操作数都需要是字符串,所以如果你想在字符串中添加一个数字,你必须做一些额外的工作:
var concat2 = str + String(2) //显示"Hi, my name is 2"
插值而不是串联的原因,这里引用 Apple 的插值介绍:"String interpolation is a way to construct a new String value from a mix of constants, variables, literals, and expressions" 换句话说,您可以对数字、布尔值等使用插值,而无需先将它们转换为字符串,您如果您使用串联,则必须这样做。
从速度的角度来看,为了区分连接(value1 + "-" + value2
)和插值("\(value1)-\(value2)"
),结果可能取决于为获得最终字符串所做的操作次数。
我在 iPhone 8 上的结果表明:
- 如果大约有 < 30 个子字符串连接在一起,则连接速度更快
- 如果大约有 > 30 个子字符串连接在一起,则插值速度更快
感谢 Sirens 发现一个并不总是比另一个快!
亲自尝试(不要忘记根据您的需要调整经过测试的字符集和迭代):
import UIKit
class ViewController: UIViewController {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
DispatchQueue.global(qos: .default).async {
ViewController.buildDataAndTest()
}
}
private static func buildDataAndTest(times: Int = 1_000) {
let characterSet = CharacterSet.alphanumerics
characterSet.cacheAllCharacters()
let data: [(String, String)] = (0 ..< times).map { _ in
(characterSet.randomString(length: 50), characterSet.randomString(length: 20))
}
_ = testCIA(data)
_ = testInterpol(data)
print("concatenation: " + String(resultConcatenation))
print("interpolation: \(resultInterpolation)")
}
/// concatenation in array
static var resultConcatenation: CFTimeInterval = 0
private static func testCIA(_ array: [(String, String)]) -> String {
var foo = ""
let start = CACurrentMediaTime()
for (a, b) in array {
foo = foo + " " + a + "+" + b
}
resultConcatenation = CACurrentMediaTime() - start
return foo
}
/// interpolation
static var resultInterpolation: CFTimeInterval = 0
private static func testInterpol(_ array: [(String, String)]) -> String {
var foo = ""
let start = CACurrentMediaTime()
for (a, b) in array {
foo = "\(foo) \(a)+\(b)"
}
resultInterpolation = CACurrentMediaTime() - start
return foo
}
}
extension CharacterSet {
static var cachedCharacters: [Character] = []
public func cacheAllCharacters() {
CharacterSet.cachedCharacters = characters()
}
/// extracting characters
///
public func characters() -> [Character] {
return codePoints().compactMap { UnicodeScalar([=10=]) }.map { Character([=10=]) }
}
public func codePoints() -> [Int] {
var result: [Int] = []
var plane = 0
for (i, w) in bitmapRepresentation.enumerated() {
let k = i % 8193
if k == 8192 {
plane = Int(w) << 13
continue
}
let base = (plane + k) << 3
for j in 0 ..< 8 where w & 1 << j != 0 {
result.append(base + j)
}
}
return result
}
//
public func randomString(length: Int) -> String {
let charArray = CharacterSet.cachedCharacters
let charArrayCount = UInt32(charArray.count)
var randomString = ""
for _ in 0 ..< length {
randomString += String(charArray[Int(arc4random_uniform(charArrayCount))])
}
return randomString
}
}
在具体处理非可选的 String
值时,字符串插值和字符串连接之间的区别是什么?
struct MyModel {
let value1: String
let value2: String
var displayNameByConcatenation: String {
return value1 + "-" + value2
}
var displayNameByInterpolation: String {
return "\(value1)-\(value2)"
}
}
- 是否会出现
displayNameByConcatenation
和displayNameByInterpolation
不同的情况?喜欢长 unicode 字符串吗? - 是否有可能以某种方式覆盖运算符
+
的行为或插值的行为以使它们在上面的示例中有所不同? - 一个 faster/slower 比另一个好吗?
请注意,从 description
。但是 String
连接(运算符 +
)是否也调用 description
?
字符串插值:
- 减少打字
- 内部调用字符串
- 在 运行 时间内更快
一个缺点:
- 分隔你的字符串
插值和拼接各有优缺点
需要使用与预定义字符串的连接以获得更好的性能
"Concatenation allows you to combine to strings together and it only works on two strings."
更新。不确定 Swift 的早期版本允许什么,但目前您可以在同一语句中将 2 个以上的字符串连接在一起:
设 str = "Hi, my name is "
var concat = str + "2" + "3" + "4" + "5" + "works" //显示 "Hi, my name is 2345 works"
因为+的两个操作数都需要是字符串,所以如果你想在字符串中添加一个数字,你必须做一些额外的工作:
var concat2 = str + String(2) //显示"Hi, my name is 2"
插值而不是串联的原因,这里引用 Apple 的插值介绍:"String interpolation is a way to construct a new String value from a mix of constants, variables, literals, and expressions" 换句话说,您可以对数字、布尔值等使用插值,而无需先将它们转换为字符串,您如果您使用串联,则必须这样做。
从速度的角度来看,为了区分连接(value1 + "-" + value2
)和插值("\(value1)-\(value2)"
),结果可能取决于为获得最终字符串所做的操作次数。
我在 iPhone 8 上的结果表明:
- 如果大约有 < 30 个子字符串连接在一起,则连接速度更快
- 如果大约有 > 30 个子字符串连接在一起,则插值速度更快
感谢 Sirens 发现一个并不总是比另一个快!
亲自尝试(不要忘记根据您的需要调整经过测试的字符集和迭代):
import UIKit
class ViewController: UIViewController {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
DispatchQueue.global(qos: .default).async {
ViewController.buildDataAndTest()
}
}
private static func buildDataAndTest(times: Int = 1_000) {
let characterSet = CharacterSet.alphanumerics
characterSet.cacheAllCharacters()
let data: [(String, String)] = (0 ..< times).map { _ in
(characterSet.randomString(length: 50), characterSet.randomString(length: 20))
}
_ = testCIA(data)
_ = testInterpol(data)
print("concatenation: " + String(resultConcatenation))
print("interpolation: \(resultInterpolation)")
}
/// concatenation in array
static var resultConcatenation: CFTimeInterval = 0
private static func testCIA(_ array: [(String, String)]) -> String {
var foo = ""
let start = CACurrentMediaTime()
for (a, b) in array {
foo = foo + " " + a + "+" + b
}
resultConcatenation = CACurrentMediaTime() - start
return foo
}
/// interpolation
static var resultInterpolation: CFTimeInterval = 0
private static func testInterpol(_ array: [(String, String)]) -> String {
var foo = ""
let start = CACurrentMediaTime()
for (a, b) in array {
foo = "\(foo) \(a)+\(b)"
}
resultInterpolation = CACurrentMediaTime() - start
return foo
}
}
extension CharacterSet {
static var cachedCharacters: [Character] = []
public func cacheAllCharacters() {
CharacterSet.cachedCharacters = characters()
}
/// extracting characters
///
public func characters() -> [Character] {
return codePoints().compactMap { UnicodeScalar([=10=]) }.map { Character([=10=]) }
}
public func codePoints() -> [Int] {
var result: [Int] = []
var plane = 0
for (i, w) in bitmapRepresentation.enumerated() {
let k = i % 8193
if k == 8192 {
plane = Int(w) << 13
continue
}
let base = (plane + k) << 3
for j in 0 ..< 8 where w & 1 << j != 0 {
result.append(base + j)
}
}
return result
}
//
public func randomString(length: Int) -> String {
let charArray = CharacterSet.cachedCharacters
let charArrayCount = UInt32(charArray.count)
var randomString = ""
for _ in 0 ..< length {
randomString += String(charArray[Int(arc4random_uniform(charArrayCount))])
}
return randomString
}
}