# Swift Slices and Subsequences: How ArraySlice Works

Source: https://devdocs10.com/articles/swift/swift-slices-subsequences  
By Murat Bo · Published 2026-05-12 · DevDocs10 (https://devdocs10.com)

Swift collections let you work with only part of a collection without immediately copying all its elements. That feature appears as slices and subsequences. Understanding how they work is important because a slice often looks like an array, but it is not the same type and it keeps the original collection’s indexing behavior. In this article, you will learn what Swift slices and subsequences are, how to create them, when to use them, and what mistakes beginners commonly run into.

> **Quick answer:** In Swift, a slice is a view into part of a collection, and a subsequence is the type returned when you take that part. For arrays, the subsequence type is usually `ArraySlice`. It shares storage with the original collection and keeps the original indexes instead of starting at zero.

> **Difficulty:** Intermediate
>
> **Helpful to know first:** You will understand this better if you already know basic Swift arrays, ranges such as `0...2` and `1..<4`, and how collection indexes work at a beginner level.

## 1. What Is a Slice or Subsequence?

A slice is a partial view of a collection. Instead of creating a brand-new collection with copied values, Swift can return a subsection of an existing collection. The general name for that returned partial collection is a `SubSequence`.

For example, when you take part of an `Array`, Swift usually gives you an `ArraySlice`. That slice contains some of the original elements, but it is not the same thing as a full `Array`.

- A slice represents only part of a collection.
- A subsequence is the type returned for that partial view.
- For arrays, the subsequence type is commonly `ArraySlice`.
- Slices often share storage with the original collection.
- A slice keeps the original index positions rather than automatically restarting at zero.

That last point is the one that surprises many developers. If you slice an array starting at index 2, the first valid index in the slice is still 2, not 0.

## 2. Why Slices and Subsequences Matter

Slices matter because they make it efficient to work with part of a collection. If you only need a few elements from a larger array or string-based collection, a slice can avoid unnecessary copying.

They are especially useful when you want to:

- Process only the first few or last few items of a collection.
- Skip elements with methods like `dropFirst()` or `dropLast()`.
- Split parsing work into smaller pieces.
- Pass a partial collection into helper logic without building a new array immediately.

However, slices are not always the best final type to keep around long term. Because they usually reference the original collection’s storage, keeping a small slice can also keep a much larger original collection alive in memory.

## 3. Basic Syntax

### Creating a slice with a range

The simplest way to create a slice is to use a range on a collection.

```swift
let numbers = [10, 20, 30, 40, 50]
let middle = numbers[1..<4]

print(middle)
print(type(of: middle))
```

Output (tested with Swift 6.4):

```text
[20, 30, 40]
ArraySlice<Int>
```

This creates a slice containing the elements at indexes 1, 2, and 3. The result is an `ArraySlice<Int>`, not an `Array<Int>`.

### Understanding the indexes

Even though `middle` contains three elements, its indexes still match the original array.

```swift
let numbers = [10, 20, 30, 40, 50]
let middle = numbers[1..<4]

print(middle.startIndex)
print(middle[1])
```

Output (tested with Swift 6.4):

```text
1
20
```

The first print call shows the starting index of the slice. The second line works because index 1 is valid in this slice. Trying to use index 0 here would fail.

### Converting a slice into a new array

If you want a separate array with zero-based indexing, create one explicitly.

```swift
let numbers = [10, 20, 30, 40, 50]
let middleSlice = numbers[1..<4]
let middleArray = Array(middleSlice)

print(middleArray[0])
```

Output (tested with Swift 6.4):

```text
20
```

This creates a new array that contains the sliced values as its own collection.

## 4. Step-by-Step Examples

### Example 1: Taking a range from an array

This is the most direct slice example. It returns part of an array without building a new array first.

```swift
let scores = [85, 90, 78, 92, 88]
let selectedScores = scores[1...3]

print(selectedScores)
```

Output (tested with Swift 6.4):

```text
[90, 78, 92]
```

The slice contains 90, 78, and 92. Because the range is closed with `...`, the end index is included.

### Example 2: Using prefix and suffix

Swift has convenient methods for taking the beginning or end of a collection.

```swift
let letters = ["A", "B", "C", "D", "E"]

let firstThree = letters.prefix(3)
let lastTwo = letters.suffix(2)

print(firstThree)
print(lastTwo)
```

Output (tested with Swift 6.4):

```text
["A", "B", "C"]
["D", "E"]
```

Both `prefix` and `suffix` return subsequences. For an array, that means slices rather than full arrays.

### Example 3: Dropping elements

Dropping values is another common way to get a subsequence.

```swift
let queue = ["first", "second", "third", "fourth"]

let remaining = queue.dropFirst()

print(remaining)
```

Output (tested with Swift 6.4):

```text
["second", "third", "fourth"]
```

`dropFirst()` returns everything except the first element. The result is still a subsequence view of the original collection.

### Example 4: Iterating safely over a slice

When you are reading values, it is often best to iterate directly instead of assuming zero-based indexes.

```swift
let temperatures = [18, 20, 22, 24, 26]
let afternoon = temperatures[2...4]

for value in afternoon {
    print(value)
}
```

Output (tested with Swift 6.4):

```text
22
24
26
```

This works well because it does not depend on any specific indexes. That makes your code easier to reason about.

## 5. Practical Use Cases

- Reading just the first few results from a larger search result array.
- Skipping a header row and processing the remaining records.
- Taking the last few log entries for display in a debugging tool.
- Parsing token streams where helper functions consume only part of a collection.
- Breaking large data sets into smaller windows for analysis.
- Working with prefixes or suffixes before deciding whether a full copy is necessary.

## 6. Common Mistakes

### Mistake 1: Assuming a slice starts at index 0

This is the most common problem with `ArraySlice`. A slice keeps the indexes from the original array.

**Problem:** This code assumes the first valid index of the slice is zero, but the slice actually starts at index 1. That causes an out-of-bounds access at runtime.

```swift
let numbers = [10, 20, 30, 40]
let part = numbers[1...2]

print(part[0])
```

**Fix:** Use the slice’s real indexes, or convert it to an array if you need zero-based indexing.

```swift
let numbers = [10, 20, 30, 40]
let part = numbers[1...2]

print(part[part.startIndex])

let copiedPart = Array(part)
print(copiedPart[0])
```

Output (tested with Swift 6.4):

```text
20
20
```

The corrected version works because it respects the slice’s actual index model or creates a new array with fresh indexing.

### Mistake 2: Expecting an Array when Swift returns ArraySlice

Many methods such as `prefix`, `suffix`, and `dropFirst` return subsequences, not full arrays.

**Problem:** This code tries to assign an `ArraySlice<Int>` to a variable typed as `[Int]`, which leads to a type mismatch such as “Cannot convert value of type 'ArraySlice<Int>' to specified type '[Int]'”.

```swift
let values = [1, 2, 3, 4]
let firstTwo: [Int] = values.prefix(2)
```

**Fix:** Either keep the result as a slice or convert it explicitly to an array.

```swift
let values = [1, 2, 3, 4]
let firstTwoSlice = values.prefix(2)
let firstTwoArray: [Int] = Array(values.prefix(2))
```

The corrected version works because it matches the actual return type or performs an explicit conversion.

### Mistake 3: Keeping a small slice for too long

A slice often shares the original collection’s storage. That is efficient for short-term work, but it can be wasteful if the original collection is very large and you keep only a tiny slice.

**Problem:** This code stores a tiny slice from a large array and may keep the large array’s storage alive longer than expected.

```swift
let bigArray = Array(1...100000)
let smallView = bigArray[0...2]
```

**Fix:** If you need to store only the small result long term, convert it into a new array.

```swift
let bigArray = Array(1...100000)
let smallView = Array(bigArray[0...2])
```

The corrected version works because the new array owns only the elements you want to keep.

### Mistake 4: Confusing ArraySlice with Array in APIs

Some functions are written to accept only arrays, even though a slice would contain compatible elements.

**Problem:** This code passes an `ArraySlice<String>` to a function that expects `[String]`, so the call fails to compile.

```swift
func printNames(_ names: [String]) {
    for name in names {
        print(name)
    }
}

let allNames = ["Ana", "Ben", "Cara"]
let someNames = allNames[1...2]

printNames(someNames)
```

**Fix:** Convert the slice to an array, or design the function to accept a broader collection type when appropriate.

```swift
func printNames(_ names: [String]) {
    for name in names {
        print(name)
    }
}

let allNames = ["Ana", "Ben", "Cara"]
let someNames = Array(allNames[1...2])

printNames(someNames)
```

Output (tested with Swift 6.4):

```text
Ben
Cara
```

The corrected version works because the function receives the exact type it expects.

## 7. Best Practices

### Use slices for short-term, efficient views

If you only need to inspect or process part of a collection briefly, a slice is a good choice because it avoids an immediate copy.

```swift
let readings = [5, 10, 15, 20, 25]
let recent = readings.suffix(2)

for value in recent {
    print(value)
}
```

Output (tested with Swift 6.4):

```text
20
25
```

This is efficient and clear when the slice is used immediately.

### Convert to Array when you need independent storage or zero-based indexing

If later code expects an array, or if you need predictable zero-based indexes, convert the slice explicitly.

```swift
let items = ["pen", "book", "lamp", "desk"]
let selection = Array(items[1...2])

print(selection[0])
```

Output (tested with Swift 6.4):

```text
book
```

This makes the collection behave like a normal standalone array.

### Prefer iteration over manual index assumptions

Many slice-related bugs happen because code assumes indexes restart at zero. Iteration usually avoids that issue entirely.

```swift
let data = [100, 200, 300, 400]
let segment = data[1...3]

for value in segment {
    print(value)
}
```

Output (tested with Swift 6.4):

```text
200
300
400
```

This approach is often safer and easier to read than manual numeric indexing.

## 8. Limitations and Edge Cases

- An `ArraySlice` is not automatically interchangeable with `Array`. You may need `Array(slice)`.
- Slice indexes usually preserve the original collection’s positions, which can surprise developers expecting zero-based access.
- Keeping a small slice can keep a large original collection’s storage alive longer than intended.
- Methods like `prefix`, `suffix`, `dropFirst`, and range subscripting often return subsequences, not full collections.
- Different collection types can have different subsequence types. `ArraySlice` is common for arrays, but `SubSequence` is a broader collection concept.
- If a range is outside valid bounds, your program can crash at runtime due to invalid indexing.

## 9. Practical Mini Project

This mini project shows a realistic use of slices. We will take the latest three messages from a chat history, print them, and then convert them to an array for a function that expects an array.

```swift
func displayMessages(_ messages: [String]) {
    for message in messages {
        print("- \(message)")
    }
}

let chatHistory = [
    "Hello",
    "How are you?",
    "I am fine",
    "Are you free later?",
    "Yes, after 6"
]

let latestMessagesSlice = chatHistory.suffix(3)

print("Latest messages as a slice:")
for message in latestMessagesSlice {
    print(message)
}

let latestMessagesArray = Array(latestMessagesSlice)

print("Formatted output:")
displayMessages(latestMessagesArray)
```

Output (tested with Swift 6.4):

```text
Latest messages as a slice:
I am fine
Are you free later?
Yes, after 6
Formatted output:
- I am fine
- Are you free later?
- Yes, after 6
```

This example shows both common patterns. First, use the slice directly for short-term iteration. Then convert it to an array when another API expects array input.

## 10. Key Points

- A slice is a view into part of a collection rather than a brand-new copied collection.
- A subsequence is the general type concept for that partial collection result.
- For arrays, slices are usually represented as `ArraySlice`.
- `ArraySlice` keeps the original indexes instead of restarting at zero.
- Methods like `prefix`, `suffix`, and `dropFirst` often return slices.
- Convert a slice with `Array(slice)` when you need an actual array.
- Long-term storage of a small slice can unintentionally keep a large collection in memory.

## 11. Practice Exercise

Try this exercise to confirm that you understand both slices and array conversion.

- Create an array of seven integers.
- Take a slice containing the middle three elements.
- Print the slice directly.
- Convert the slice to an array.
- Print the first element of the new array using index 0.

**Expected output:** You should see the three middle values printed as a slice, followed by the first value from the converted array.

**Hint:** Use a range such as `2...4` and then call `Array(...)` on the slice.

```swift
let numbers = [5, 10, 15, 20, 25, 30, 35]

let middleSlice = numbers[2...4]
print(middleSlice)

let middleArray = Array(middleSlice)
print(middleArray[0])
```

Output (tested with Swift 6.4):

```text
[15, 20, 25]
15
```

## 12. Final Summary

Swift slices and subsequences let you work with part of a collection efficiently. For arrays, that usually means working with `ArraySlice`, which shares storage with the original array and preserves the original indexes. That makes slices fast and useful for short-term operations such as taking a prefix, suffix, or range.

The most important thing to remember is that a slice is not the same as an array. It may not start at index 0, it may not match APIs expecting `[Element]`, and it may keep the original collection alive in memory. When you need independent storage or array-style indexing, convert the slice explicitly with `Array(slice)`.

A good next step is to study Swift collection indexes and range operators in more detail, because those concepts make slices much easier to use correctly and confidently.
