What the rule is
In Swift you can't replace one character of a string through its index. A string's subscript can only read characters; it is get-only. This code doesn't compile:
var name = "bndrei"
name[name.startIndex] = "A"
error: cannot assign through subscript: subscript is get-only
The same error appears when you write an integer position, name[0] = "A", as the starter code of this lesson does. Even with the right kind of index, assignment through the subscript is not allowed.
Part of the reason is that a Swift string is a sequence of Unicode characters, and one character can take a different number of bytes than the next. Replacing one in place could mean shifting everything after it, so Swift asks you to build the new text explicitly instead.
What can change
This does not mean a string variable is frozen. It means characters can't be swapped one at a time by position. Two things decide what you can do:
varorlet. A string declared withvarcan be reassigned, and it can also be changed in place with methods such asappend,insertandreplaceSubrange. A string declared withletcan't change at all, and trying to callappendon it is a compile error.- Value semantics. A
Stringis a value type. Assigning it to another variable gives that variable its own independent copy, so changing one never affects the other.
let fixed = "Hello"
var copy = fixed
copy.append("?")
print(fixed, copy)
Hello Hello?
Three ways to change a string
1. Reassign a whole new value
The simplest fix is to give the variable a new string, built from pieces of the old one:
var message = "Jello world"
message = "Hello world"
print(message)
Hello world
2. Edit in place with a mutating method
replaceSubrange takes a range of indices and the text to put there. Replacing the range that holds only the first character changes just that character:
var message = "Jello world"
message.replaceSubrange(message.startIndex...message.startIndex, with: "H")
print(message)
Hello world
3. Work on an array of characters
An Array can be changed by position. Convert the string with Array(...), change the element, and convert back with String(...):
var chars = Array("Jello")
chars[0] = "H"
print(String(chars))
Hello
The exercise
The variable name holds "bndrei Chiriac", and it should hold "Andrei Chiriac". Only the first character is wrong, but name[0] = "A" can't be compiled. To fix it:
- Take everything after the first character with
name.dropFirst(). That gives aSubstringwith the value"ndrei Chiriac". - Convert it with
String(...)to get a realString. - Put
"A"in front with+, which joins two strings into a new one, and assign the result back toname.
var name = "bndrei Chiriac"
// Change code below:
name = "A" + String(name.dropFirst())
print(name)
Andrei Chiriac
The right-hand side is evaluated first, using the old value of name, and only then is the new string stored in the variable. The old string isn't modified; name just points to a new value.
Common mistakes
- Trying to assign through the subscript.
name[index] = "A"never compiles, whatever the index. - Using
let. The fix above reassignsname, so the variable must be declared withvar. - Forgetting
String(...).dropFirst()returns aSubstring, and assigning aSubstringto aStringvariable is a compile error (cannot assign value of type 'Substring' to type 'String'). Wrap it inString(...). - Expecting a copy to change too. After
var copy = original, editingcopyleavesoriginalas it was.
Key takeaways
- A string's subscript is get-only: you can read a character by index, but never assign to it.
- A
varstring can be reassigned or changed with methods such asappend,insertandreplaceSubrange. Aletstring can't change. - To change one character, build a new string from pieces, as in
"A" + String(name.dropFirst()).
