字符串插值和字符串连接之间的区别

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)"
    }
}

请注意,从 我们了解到字符串插值将使用 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
    }
}