From fixed to flexible
The previous lesson created arrays whose size never changed. A Swift array declared with var can do more: it can grow and shrink while the program runs, with append to add an element and remove(at:) to take one out. The type is the same Array, written [Element]. What makes the difference is the keyword you declare it with.
var sandwich: [String] = ["bread"]
sandwich.append("jelly")
print(sandwich) // ["bread", "jelly"]
sandwich.remove(at: 0)
print(sandwich) // ["jelly"]
If sandwich were declared with let, both calls would be compile errors, because a let array can't change in any way.
Ways to create an array
An empty array
To start with nothing, name the element type and add empty parentheses:
var empty = [String]()
print(empty.count) // 0
The compiler needs the element type, because an empty pair of brackets gives it nothing to infer from. That is why [String] appears here.
A type annotation
You can state the type on the variable instead, and then assign an empty literal:
var sandwich: [String] = []
The annotation after the colon says what the variable holds. Writing var sandwich = [] without it fails to compile, since the element type can't be guessed. Annotations are also useful when you want a different type from the one Swift would infer, for example let weights: [Double] = [1, 2, 3] stores doubles, while [1, 2, 3] alone would infer [Int].
An array literal
If you already know the items, list them between brackets, separated by commas:
var sandwich: [String] = [
"peanut butter", "jelly", "bread"
]
print(sandwich.count) // 3
A literal can span several lines, and Swift also accepts a trailing comma after the last item. With the values in place, the annotation is optional: var sandwich = ["peanut butter", "jelly", "bread"] is inferred as [String].
Arrays are values
Assigning an array to another variable copies it, so later changes to one don't affect the other:
var original = [14, 32, 50]
var backup = original
original[0] = 99
print(original) // [99, 32, 50]
print(backup) // [14, 32, 50]
This differs from languages where two names share one array.
The exercise, step by step
- Create
fruits. Declare it withletand an array literal holding"mango","kiwi"and"grapefruit". Swift infers[String]from the values, so no annotation is needed. - Create
ages. Declare it withletand the literal[14, 32, 50, 21]. These are whole numbers, so the type is[Int].
let fruits = ["mango", "kiwi", "grapefruit"]
let ages = [14, 32, 50, 21]
Both are constants. If a later task needs to add to them, change let to var at that point.
Common mistakes
- Using
letand then appending.letarrays rejectappend,remove(at:)and element assignment. The error message says the array is aletconstant. - Using
varfor everything. The code works, butlettells readers, and the compiler, that the array never changes. - Forgetting the type for an empty array.
var items = []doesn't compile. Write[String]()orvar items: [String] = []. - Mixing types in a literal.
[14, "thirty"]is rejected with a message about a heterogeneous collection literal, unless you annotate the array as[Any], which gives up the type checking. Keep each array to one element type.
Key takeaways
- A
vararray can change size withappendandremove(at:); aletarray can't change. - Create an empty array with
[Type]()or with an annotation and[]. - An array literal lists the items and lets Swift infer the type.
- Assigning an array copies it.
