代码之家  ›  专栏  ›  技术社区  ›  Fawkes

为什么swift编译器将此标记为错误?

  •  6
  • Fawkes  · 技术社区  · 6 年前

    我有两种编写相同代码的方法,其中一种似乎不受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引用该变量,然后尝试下标,则此操作不起作用。

    我还知道,如果范围是string.index类型或其他新的方式,它可能在“非工作代码”中工作。

    有人能解释为什么吗?这是swift编译器中的一个错误吗?swift编译器已经有足够的“扭曲”字符串逻辑了。

    1 回复  |  直到 6 年前
        1
  •  5
  •   Martin R    6 年前

    有几个 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))