Swift编译器为何将其标记为错误?

时间:2018-11-15 14:01:33

标签: swift string range subscript swift4.2

我有两种编写相同代码的方式,其中一种似乎被Swift编译器所讨厌。你能解释为什么吗?

上下文:

let guaranteedValue: String
let cursorPositionFromEnd: Int

工作代码:

let stringFromEndUntilCursorPosition = String(guaranteedValue.reversed()[0..<cursorPositionFromEnd])

无效代码:

let reversedOriginalString = guaranteedValue.reversed()
let stringFromEndUntilCursorPosition = String(reversedOriginalString[0..<cursorPositionFromEnd])

编译器错误消息:“无法为类型为ReversedCollection<String>的索引下标为Range<Int>的值”

其他工作尝试:

let reversedOriginalString = guaranteedValue.reversed()[0..< cursorPositionFromEnd]
let stringFromEndUntilCursorPosition = String(reversedOriginalString)

基本上的想法是,如果在函数返回处添加索引,则只能下标一个反向范围{但可能不仅可以下标},但是如果首先使用let或var引用变量然后尝试下标,则该方法不起作用它。

我还理解,如果Range为String.Index类型或采用这种新方式的话,它可能会在“非工作代码”中起作用。

谁能解释为什么?这是Swift编译器中已经有足够的“扭曲”字符串逻辑的错误吗?

1 个答案:

答案 0 :(得分:5)

有几种reversed()方法,如What trouble could bring assining reversed() to a swift array?中所述。

在您的第一个代码示例中,

let stringFromEndUntilCursorPosition = String(guaranteedValue.reversed()[0..<cursorPositionFromEnd])

编译器从上下文(即下标)推断出 需要Sequence.reversed()方法,该方法返回一个数组。数组由整数索引, 因此代码可以编译。此方法的复杂度为O(n),因为 创建具有所有元素的新数组。

let reversedOriginalString = guaranteedValue.reversed()

没有这样的上下文,编译器选择 Bidirectional.reversed()方法。与上述方法相比,该方法具有 O(1)的复杂性。它返回一个ReversedCollection 有自己的索引类型,因此

let stringFromEndUntilCursorPosition = String(reversedOriginalString[0..<cursorPositionFromEnd])

产生观察到的错误消息。

可能的解决方案:

  • 提供上下文以强制创建数组:

    let reversedOriginalString: [Character] = guaranteedValue.reversed()
    // Or: let reversedOriginalString: Array = guaranteedValue.reversed()
    // Or: let reversedOriginalString = guaranteedValue.reversed() as Array
    let stringFromEndUntilCursorPosition = String(reversedOriginalString[0..<cursorPositionFromEnd])
    

    这有效,但是具有创建临时数组的缺点。

  • 对反向集合进行正确的索引计算:

    let reversedOriginalString = guaranteedValue.reversed()
    let pos = reversedOriginalString.index(reversedOriginalString.startIndex, offsetBy: cursorPositionFromEnd)
    let stringFromEndUntilCursorPosition = String(reversedOriginalString[..<pos])
    

    这避免了中间数组,但是编写起来很繁琐。

  • 使用prefix(maxLength:)序列方法:

    let reversedOriginalString = guaranteedValue.reversed()
    let stringFromEndUntilCursorPosition = String(reversedOriginalString.prefix(cursorPositionFromEnd))