21

I fail to understand the problem Xcode is confronting me with in this line:

iteration.template = template[iterationSubstring.endIndex...substring.startIndex]

template is a String and iterationSubstring and substring are Substrings of template. Xcode highlights the opening square bracket with the following message:

Subscript 'subscript(_:)' requires the types 'Substring.Index' and 'Int' be equivalent

The error message does not make any sense to me. I try to obtain a Substring by creating a Range<String.Index> with the [template.startIndex...template.endIndex] subscript. How is this related to Int? And why does the same pattern work elsewhere?


Xcode playground code reproducing the problem:

import Foundation
let template = "This is an ordinary string literal."

let firstSubstringStart = template.index(template.startIndex, offsetBy: 5)
let firstSubstringEnd = template.index(template.startIndex, offsetBy: 7)
let firstSubstring = template[firstSubstringStart...firstSubstringEnd]

let secondSubstringStart = template.index(template.startIndex, offsetBy: 10)
let secondSubstringEnd = template.index(template.startIndex, offsetBy: 12)
let secondSubstring = template[secondSubstringStart...secondSubstringEnd]

let part: String = template[firstSubstring.endIndex...secondSubstring.startIndex]

After all I have a template string and two substrings of it. I want to get a String ranging from the end of the first Substring to the start of the second Substring.

p13n
  • 859
  • 8
  • 31
  • What type is your property `template`? Seems that it is declared as `String`. The main issue is the use of a `ClosedRange` instead of `Range` and type mismatch trying to assign a `Substring` to a `String` or a combination of both. try `let part: String = template[template.startIndex...template.endIndex]` would throw `Subscript 'subscript(_:)' requires the types 'String.Index' and 'Int' be equivalent` – Leo Dabus Feb 06 '20 at 13:30
  • @MartinR I updated the playground code to reproduce my problem in the first snippet. – p13n Feb 06 '20 at 13:44
  • 1
    @LeoDabus `template` indeed is a `String`. I forgot to mention that. Indeed it was an actually obvious type mismatch. Oops. Xcode really distracted me from that. – p13n Feb 06 '20 at 13:45

1 Answers1

24

The current version of Swift works with the Substring struct which is a sliced String.

The error seems to be misleading and occurs if you are going to assign a (range-subscripted) Substring to a String variable.

To fix the error create a String from the Substring

iteration.template = String(template[iterationSubstring.endIndex...substring.startIndex])

Nevertheless you are strongly discouraged from creating ranges with indices from different strings (iterationSubstring and substring). Slice the main string, the indices are preserved.


The crash in the second (meanwhile deleted) example occurred because the last character of a string is at index before endIndex, it's

template[template.startIndex..<template.endIndex] 

or shorter

template[template.startIndex...]
vadian
  • 274,689
  • 30
  • 353
  • 361
  • 1
    Indeed it was misleading! I attempted to assign a `Substring` to a `String`. Wrapping it into `String()` solves the issue. I still need to get used to this. I will elaborate on my original question, too, as @MartinR suggested. – p13n Feb 06 '20 at 13:35
  • After your edit: `part` is `Substring` even if you annotate `String` which causes the mentioned error. Remove the annotation and create a string with `String(...)`. To get the substring you can also write `template[firstSubstringEnd.. – vadian Feb 06 '20 at 13:49
  • In the real project code the equivalent of `part` is a `String` property on an object to keep things separated. I added the type annotation in the playground code for explanation. It is necessary to produce the misleading error. – p13n Feb 06 '20 at 13:59
  • By the way you can write shorter: `let firstSubstringEnd = template.index(template.startIndex, offsetBy: 8); let secondSubstringStart = template.index(template.startIndex, offsetBy: 10); let part = template[firstSubstringEnd...secondSubstringStart]` – vadian Feb 06 '20 at 14:03
  • 1
    This is bug [SR-11702](https://bugs.swift.org/browse/SR-11702), and has been fixed on master. – Martin R Feb 06 '20 at 14:16