【问题标题】:Difference between String interpolation and String concatenation字符串插值和字符串连接的区别
【发布时间】:2017-08-08 12:58:07
【问题描述】:

当专门处理非可选的String 值时,字符串插值和字符串连接有什么区别?

struct MyModel {
    let value1: String
    let value2: String
    var displayNameByConcatenation: String {
        return value1 + "-" + value2
    }
    var displayNameByInterpolation: String {
        return "\(value1)-\(value2)"
    }
}
  • 是否存在displayNameByConcatenationdisplayNameByInterpolation 不同的情况?喜欢长 unicode 字符串?
  • 是否有可能以某种方式覆盖运算符+ 的行为或插值的行为以使它们在上述示例中有所不同?
  • 一个比另一个快/慢吗?

请注意,从this question 中我们了解到字符串插值将使用 CustomStringConvertible 的 description。但是String 连接(运算符+)是否也调用description

【问题讨论】:

  • 我认为我们可以放心地假设 stringdescription 返回字符串本身,这意味着没有区别。
  • 您是否尝试覆盖+?你测量速度了吗?
  • @MartinR 速度测试完成,使用您的一些 CharacterSet 代码来获得乐趣。

标签: swift string swift3 string-concatenation string-interpolation


【解决方案1】:

从速度的角度来看,要区分串联 (value1 + "-" + value2) 和插值 ("\(value1)-\(value2)"),结果可能取决于为获得最终字符串所执行的操作数。

我在 iPhone 8 上的结果表明:

  • 如果大约有
  • 如果大约有 > 30 个子串要连接在一起,那么插值会更快

感谢警报器发现一个并不总是比另一个快!

自己尝试一下(不要忘记根据您的需要调整测试的字符集和迭代):

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
    /// https://stackoverflow.com/a/52133647/1033581
    public func characters() -> [Character] {
        return codePoints().compactMap { UnicodeScalar($0) }.map { Character($0) }
    }
    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
    }

    // http://stackoverflow.com/a/42895178/1033581
    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
    }
}

【讨论】:

  • 我会多次运行这个测试,以确保这个声明在统计上是有效的。
  • 我在 iPad Pro 上得到了相反的结果。连接需要 8.51,而插值需要 1.99。斯威夫特 4.1,-O -Ofast
  • 我认为您上面的输出是针对未包含@DielsonSales 建议的单次迭代。这是在 12.1 的 2018 iPad Pro 上完成的
  • @Sirens 感谢您的关注:帖子已更新以反映根据迭代次数的不同,最快的并不总是相同的。
【解决方案2】:

“连接允许您将字符串组合在一起,它只适用于两个字符串。”

更新。不确定 Swift 的早期版本允许什么,但目前您可以在同一个语句中将 2 个以上的字符串连接在一起:

let str = "嗨,我叫"

var concat = str + "2" + "3" + "4" + "5" + "works" //显示“嗨,我叫 2345works”

因为 + 的两个操作数都需要是字符串,所以如果你想给字符串加一个数字,你还需要做一些额外的工作:

var concat2 = str + String(2) //显示“嗨,我叫 2”

为什么使用插值而不是串联,这里引用了 Apple 的插值介绍:“字符串插值是一种从常量、变量、文字和表达式的组合中构造新字符串值的方法”换句话说,您可以对数字、布尔值等使用插值,而无需先将它们转换为字符串,如果使用串联,则必须这样做。

【讨论】:

【解决方案3】:

字符串插值:

  • 少打字
  • 内部调用字符串
  • 运行时更快

一个缺点:

  • 分隔你的字符串

插值和连接各有优缺点

需要使用与预定义字符串连接以获得更好的性能

【讨论】:

  • 所以字符串插值更快?是来自测试、文档还是逻辑推导?
  • 如果它的动态字符串 - 插值通过测试更快。你可以在插值中使用数字、枚举等
猜你喜欢
  • 2012-10-10
  • 2019-01-12
  • 1970-01-01
  • 1970-01-01
  • 2015-07-11
  • 2014-06-12
  • 1970-01-01
  • 2010-09-08
  • 2017-01-29
相关资源
最近更新 更多