What a Scala String is
A Scala String is a sequence of characters, each with a zero-based index. Under the hood it is Java's String, so it brings Java's methods with it, and Scala adds collection-style helpers on top. Strings are written in double quotes:
var greeting = "Hello"
A single character is a Char and is written in single quotes, like 'H'. The two types are different: "H" is a string of length 1, 'H' is a character.
Accessing characters and getting the length
Scala reads a character with parentheses around the index, not square brackets. The property length gives the number of characters, so the last character is at length - 1:
val str = "Hello"
println(str(0)) // H
println(str(str.length - 1)) // o
println(str.length) // 5
Both results are Char values. Reading an index that doesn't exist, such as str(10), throws a StringIndexOutOfBoundsException when the code runs.
Concatenation
The + operator joins strings and produces a new one. For a var, += joins and stores the result back in the same variable:
var greet = "Welcome"
val name = "John"
greet += " back, "
greet += name
println(greet) // Welcome back, John
Every join builds a new string, so a loop that adds one piece at a time copies the growing text on each pass. For many pieces, use a StringBuilder:
val sb = new StringBuilder
sb.append("ab")
sb.append('c')
println(sb.toString) // abc
Slicing with substring
substring(startIndex, endIndex) returns the characters from startIndex up to but not including endIndex. With a single argument it goes to the end of the string:
val s = "Scala"
println(s.substring(1, 3)) // ca
println(s.substring(2)) // ala
println(s.substring(2, 4)) // al
The length of the result is endIndex - startIndex. An end index larger than the length, as in "Scala".substring(2, 6), throws a StringIndexOutOfBoundsException.
Immutability
A string can't be changed once it exists. Trying to assign to one of its positions doesn't compile:
var myStr = "Bob"
myStr(0) = 'J'
The compiler reports value update is not a member of String. What you can do is point the variable at a new string:
var myStr = "Bob"
myStr = "Job"
// or, building the new string from parts of the old one
myStr = "J" + myStr.substring(1, 3)
Notice the difference: the first string is never altered; myStr simply refers to a different one afterwards. This only works because myStr is a var. With a val, reassignment is a compile error.
Changing characters through an array
Creating a new string costs O(n), because every character is copied. If you need to change many characters, convert the string to an array, change the array, and convert back. An Array[Char] is mutable, and changing one element is O(1):
var str = "Andy"
val myArr = str.toCharArray()
myArr(0) = 'a'
myArr(2) = 'D'
str = String(myArr)
println(str) // anDy
Here String(myArr) calls the Java String constructor, and it works without new in Scala 3. The array can be a val: the variable always refers to the same array, and the elements inside it are still free to change. Another way to turn the array back into a string is myArr.mkString.
Looping over a string
The property indices is the range 0 to length - 1, so a loop can visit every position:
val myStr = "Andy"
for (i <- myStr.indices) {
println(myStr(i))
}
It prints A, n, d and y on separate lines. The loop takes O(n) time for a string of length n.
The lesson's exercise
The exercise turns "Java" into "TypeScript", using the operations above in order.
- Create a
varnamedlangholding"Java". It must be avar, because the next step changes it. - Append
"script"with+=. A new string is built and stored back, solangis"Javascript". - Create a
valnamedsubstrwithlang.substring(4), the part from index 4 to the end:"script". - Create a
varnamednewLangfrom"Type" + substr, which is"Typescript". - Copy it into a mutable array:
val charArray = newLang.toCharArray(). - Set
charArray(4)to'S'. Index 4 is the fifth character, the lowercasesofscript. - Build a string from the array with
String(charArray)and assign it tonewLang, which now holds"TypeScript".
The full solution:
var lang = "Java"
lang += "script"
val substr = lang.substring(4)
var newLang = "Type" + substr
val charArray = newLang.toCharArray()
charArray(4) = 'S'
newLang = String(charArray)
Common mistakes
- Using square brackets.
str[0]is not Scala; writestr(0). - Mixing up
CharandString.charArray(4) = "S"doesn't compile, because the array holdsCharvalues and"S"is aString. - Forgetting that the end index is excluded.
"Scala".substring(1, 3)is"ca", two characters, not three. - Expecting a method to change the string.
lang.substring(4)leaveslangas it was; only the returned value is new. - Declaring with
valand then reassigning. Usevarfor a variable that gets a new string later.
Key takeaways
- Characters are read with
s(i); the last index iss.length - 1. +and+=build new strings; aStringBuildersuits many pieces.substringexcludes the end index.- Strings are immutable. To change characters, go through an array and convert back.
