Question
In Go, what is the idiomatic way to retrieve the last element of a slice?
var slice []int
slice = append(slice, 2)
slice = append(slice, 7)
last := slice[len(slice)-1:][0] // Retrieves the last element
The code above works, but it feels awkward. Is there a cleaner and more idiomatic way to get the last item from a slice?
Short Answer
By the end of this page, you will understand how to access the last element of a slice in Go, why direct indexing is the usual approach, how to handle empty slices safely, and which slice expressions are unnecessary for this task.
Concept
In Go, a slice is a lightweight view over an underlying array. To access an element in a slice, you normally use its index.
Because Go slices are zero-indexed:
- The first element is at index
0 - The second element is at index
1 - The last element is at index
len(slice) - 1
So the idiomatic way to get the last element is:
last := slice[len(slice)-1]
This works because len(slice) gives the number of elements, and the final valid index is always one less than that count.
Your original code:
slice[len(slice)-1:][0]
first creates a new slice containing the last element, then indexes into that new slice to get the element back. It is valid, but unnecessary.
Why this matters in real programs:
- Slices are used everywhere in Go: API data, file lines, query results, queues, stacks, and more.
- Accessing the last element is common when processing sequences.
- Writing the simplest correct form makes code easier to read and maintain.
One important rule: if the slice is empty, slice[len(slice)-1] will panic because there is no last element.
Mental Model
Think of a slice like a row of numbered boxes.
If there are 5 boxes, their positions are:
01234
The total count is 5, but the last box is at position 4, which is 5 - 1.
So len(slice) tells you how many boxes exist, and len(slice)-1 tells you where the last box is.
Your original approach is like taking the last box, putting it into a tiny one-box tray, and then opening that tray to take it out again. It works, but it adds an extra step.
Syntax and Examples
The standard syntax is:
last := slice[len(slice)-1]
Example with integers
package main
import "fmt"
func main() {
nums := []int{2, 7, 10}
last := nums[len(nums)-1]
fmt.Println(last)
}
Output:
10
Example with strings
package main
import "fmt"
func main() {
names := []string{"Ana", "Ben", "Cara"}
fmt.Println(names[len(names)-1])
}
Output:
Cara
Step by Step Execution
Consider this code:
package main
import "fmt"
func main() {
nums := []int{2, 7, 11}
last := nums[len(nums)-1]
fmt.Println(last)
}
Step by step:
nums := []int{2, 7, 11}creates a slice with 3 elements.len(nums)returns3.len(nums) - 1becomes2.nums[2]accesses the element at index2.- That element is
11. lastis assigned the value11.fmt.Println(last)prints11.
Visual trace
Real World Use Cases
Getting the last element of a slice appears in many practical situations:
- Log processing: get the most recent log entry.
- Web APIs: read the last item returned by a paginated response.
- Command history: get the most recent command.
- Stack-like behavior: inspect the top item before popping it.
- Data pipelines: compare the newest value with the previous ones.
- File parsing: get the last line after splitting content.
Example: latest event in a list
events := []string{"created", "updated", "deleted"}
latest := events[len(events)-1]
Example: stack top
stack := []int{10, 20, 30}
top := stack[len(stack)-1]
These patterns are simple, direct, and common in Go programs.
Real Codebase Usage
In real Go codebases, developers usually pair direct indexing with small safety checks.
Common pattern: guard clause
if len(items) == 0 {
return errors.New("no items available")
}
last := items[len(items)-1]
This is readable and prevents panics.
Common pattern: helper function
If your code often needs the last element, you may wrap the logic:
func lastInt(nums []int) (int, bool) {
if len(nums) == 0 {
return 0, false
}
return nums[len(nums)-1], true
}
This makes callers handle the empty case explicitly.
Common pattern: stack operations
func peek(stack []string) (, ) {
(stack) == {
,
}
stack[(stack)],
}
Common Mistakes
1. Forgetting to handle empty slices
Broken code:
nums := []int{}
last := nums[len(nums)-1]
This panics.
Better:
if len(nums) == 0 {
fmt.Println("empty slice")
return
}
last := nums[len(nums)-1]
2. Using len(slice) as the last index
Broken code:
nums := []int{2, 7, 11}
fmt.Println(nums[len(nums)])
Why it fails:
len(nums)is3- Valid indexes are
0,1, and2
Correct version:
Comparisons
| Approach | Example | Works? | Idiomatic? | Notes |
|---|---|---|---|---|
| Direct indexing | slice[len(slice)-1] | Yes | Yes | Standard way to get the last element |
| Slice then index | slice[len(slice)-1:][0] | Yes | No | Unnecessary extra step |
Using len(slice) directly | slice[len(slice)] | No | No | Panics: out of range |
| Negative index | slice[-1] | No | No |
Cheat Sheet
// Get last element
last := slice[len(slice)-1]
// Safe check
if len(slice) == 0 {
// handle empty slice
}
// Last index
lastIndex := len(slice) - 1
Rules
- Go slices are zero-indexed.
- The last valid index is always
len(slice) - 1. - Accessing an invalid index causes a panic.
- Go does not support negative indexes.
- Use indexing for one element, not slicing.
Common safe pattern
if len(slice) > 0 {
last := slice[len(slice)-1]
fmt.Println(last)
}
Avoid
slice[len(slice)] // out of range
slice[-1] // invalid in Go
slice[len(slice)-1:][0] // works, but unnecessary
FAQ
What is the idiomatic way to get the last element of a slice in Go?
Use direct indexing:
last := slice[len(slice)-1]
Why is slice[len(slice)-1:][0] considered awkward?
Because it creates a one-element sub-slice and then indexes into it. It is more complicated than needed when you only want one value.
What happens if the slice is empty?
Your program will panic with an index out of range error. Always check len(slice) == 0 if the slice might be empty.
Does Go support negative indexing like slice[-1]?
No. Go does not allow negative indexes.
Can I use the same approach with a string slice or struct slice?
Yes. The pattern works with any slice type:
lastName := names[len(names)-1]
Is this the same for arrays in Go?
Yes. Arrays also use zero-based indexing, so the last element is at len(arr)-1.
Should I write a helper function for this?
If you need this often or want safer code, a helper that returns (value, ok) can be a good idea.
Mini Project
Description
Build a small Go program that stores recent scores in a slice and prints the latest score. This demonstrates how to get the last element of a slice safely, which is a common need when working with recent activity, logs, history lists, or stack-like data.
Goal
Create a program that appends several scores, prints the last score, and safely handles the case where no scores exist.
Requirements
- Create a slice of integers to hold scores.
- Append at least three scores to the slice.
- Print the last score using idiomatic slice indexing.
- Add a safety check for the empty-slice case.
- Show a second example with an empty slice.
Keep learning
Related questions
Automatic Build Versioning in Go: Embed Incrementing Build Numbers
Learn how to add automatic build versioning in Go using linker flags, build metadata, CI counters, and Git-based version values.
Blank Identifier Imports in Go: What `_` Means in an Import Statement
Learn what `_` means in a Go import, why blank identifier imports run package init code, and when to use them safely.
Calling Functions Across Files in the Same Go Package
Learn how Go uses packages across multiple files, why functions may appear undefined, and how to organize code correctly.