我有两种编写相同代码的方式,其中一种似乎被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编译器中已经有足够的“扭曲”字符串逻辑的错误吗?
答案 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))