Question
I want to delete an element from a slice in Go based on its position.
Here is my current code:
fmt.Println("Enter position to delete:")
fmt.Scanln(&pos)
newArr := make([]int, len(arr)-1)
k := 0
for i := 0; i < len(arr)-1; {
if i != pos {
newArr[i] = arr[k]
k++
i++
} else {
k++
}
}
for i := 0; i < len(arr)-1; i++ {
fmt.Println(newArr[i])
}
This code is intended to remove one element from the slice, but it does not behave correctly. What is the proper way to delete an element from a slice in Go?
Short Answer
By the end of this page, you will understand how slice deletion works in Go, why slices cannot remove elements directly, and how to create a new slice without the unwanted item using idiomatic Go code such as append(slice[:i], slice[i+1:]...). You will also learn how to handle index validation and avoid common off-by-one mistakes.
Concept
In Go, a slice is a flexible view over an underlying array. Unlike some other languages, slices do not have a built-in delete operation for removing an element by index. Instead, you create a new slice that skips the element you do not want.
The most common and idiomatic approach is:
arr = append(arr[:pos], arr[pos+1:]...)
This works by combining:
arr[:pos]→ everything before the elementarr[pos+1:]→ everything after the elementappend(...)→ joins those two parts together
Why this matters:
- Slices are used everywhere in Go for lists of data.
- Real programs often need to remove items from memory, user input, API results, or filtered data.
- Understanding slice deletion helps you write simpler and safer code.
A key point: deleting from a slice does not shrink an array in place. It creates a new slice value, often reusing the same underlying array.
You should also validate the index before deleting, because using an invalid position will cause a runtime panic.
Mental Model
Think of a slice like a train made of connected carriages.
If you want to remove one carriage in the middle, you do not "delete" it magically. Instead, you reconnect:
- the carriages before it
- to the carriages after it
So if the slice is:
[10, 20, 30, 40, 50]
and you remove index 2 (30), you reconnect:
[10, 20]- with
[40, 50]
resulting in:
[10, 20, 40, 50]
That is exactly what append(arr[:pos], arr[pos+1:]...) does.
Syntax and Examples
Core syntax
slice = append(slice[:index], slice[index+1:]...)
Example: remove an element by index
package main
import "fmt"
func main() {
arr := []int{10, 20, 30, 40, 50}
pos := 2
if pos < 0 || pos >= len(arr) {
fmt.Println("Invalid position")
return
}
arr = append(arr[:pos], arr[pos+1:]...)
fmt.Println(arr)
}
Output:
[10 20 40 50]
What this does
arr[:pos]gives all elements beforeposarr[pos+1:]gives all elements after
Step by Step Execution
Consider this code:
arr := []int{10, 20, 30, 40, 50}
pos := 2
arr = append(arr[:pos], arr[pos+1:]...)
fmt.Println(arr)
Step 1: Original slice
[10, 20, 30, 40, 50]
Indexes are:
| Index | Value |
|---|---|
| 0 | 10 |
| 1 | 20 |
| 2 | 30 |
| 3 | 40 |
| 4 | 50 |
Step 2: Take elements before pos
Real World Use Cases
Deleting an element from a slice is common in many Go programs.
Common scenarios
- Removing a completed task from a todo list
- Deleting a user-selected item from a CLI menu
- Dropping invalid records from parsed data
- Removing an item from an in-memory cache
- Excluding a failed job from a processing queue
Example: remove a product from a cart
cart := []string{"book", "pen", "bag"}
removeIndex := 1
cart = append(cart[:removeIndex], cart[removeIndex+1:]...)
fmt.Println(cart)
Output:
[book bag]
Example: remove a bad value after validation
scores := []int{90, -1, 75, 88}
badIndex := 1
scores = append(scores[:badIndex], scores[badIndex+1:]...)
fmt.Println(scores)
This pattern is useful whenever your program keeps data in memory and needs to exclude one entry.
Real Codebase Usage
In real projects, developers usually wrap slice deletion in a helper function and combine it with validation.
Common pattern: helper function
func removeAt(slice []int, index int) []int {
if index < 0 || index >= len(slice) {
return slice
}
return append(slice[:index], slice[index+1:]...)
}
This makes the code reusable and safer.
Guard clause pattern
Developers often check invalid conditions early:
if pos < 0 || pos >= len(arr) {
return
}
This avoids deeply nested logic and prevents runtime errors.
Filtering instead of deleting one index
Sometimes developers do not know the index ahead of time. In that case, they build a new slice using a condition:
result := arr[:0]
for _, v := range arr {
if v != 30 {
result = append(result, v)
}
}
arr = result
Common Mistakes
1. Not checking the index range
If pos is invalid, the program panics.
Broken code:
arr = append(arr[:pos], arr[pos+1:]...)
Safer version:
if pos < 0 || pos >= len(arr) {
fmt.Println("Invalid position")
return
}
arr = append(arr[:pos], arr[pos+1:]...)
2. Forgetting the ...
Broken code:
arr = append(arr[:pos], arr[pos+1:])
Why it fails:
appendexpects values to appendarr[pos+1:]is a slice...expands the slice into values
Correct code:
arr = append(arr[:pos], arr[pos+1:]...)
Comparisons
Slice deletion approaches
| Approach | Keeps order? | Easy to read? | Typical use |
|---|---|---|---|
append(slice[:i], slice[i+1:]...) | Yes | Yes | Standard deletion by index |
| Manual copy into new slice | Yes | No | Rarely needed for beginners |
| Replace with last element, then shorten | No | Yes | Faster removal when order does not matter |
Standard removal vs swap-with-last
Standard removal
arr = append(arr[:pos], arr[pos+1:]...)
- Preserves original order
- Most common solution
- Best default choice
Swap with last
Cheat Sheet
Delete by index
slice = append(slice[:i], slice[i+1:]...)
Safe version
if i >= 0 && i < len(slice) {
slice = append(slice[:i], slice[i+1:]...)
}
Remove last element
slice = slice[:len(slice)-1]
Remove first element
slice = slice[1:]
Fast removal when order does not matter
slice[i] = slice[len(slice)-1]
slice = slice[:len(slice)-1]
Rules to remember
- Always validate the index
- Use
...when appending a slice into another slice append(slice[:i], slice[i+1:]...)preserves order- Slices do not have a built-in
deleteby index
FAQ
How do I remove an element from a slice in Go?
Use:
slice = append(slice[:i], slice[i+1:]...)
This removes the element at index i.
Why is there no delete for slices in Go?
Because slices are views over arrays. Go expects you to build a new slice layout using slicing and append.
Do I need to create a new slice manually?
Usually no. The idiomatic append(slice[:i], slice[i+1:]...) is enough.
What happens if the index is out of range?
Your program will panic at runtime. Always check that i >= 0 && i < len(slice).
Does deleting from a slice preserve order?
Yes, the standard append(slice[:i], slice[i+1:]...) approach preserves the order of the remaining elements.
Is there a faster way if I do not care about order?
Yes:
slice[i] = slice[len(slice)-1]
slice = slice[:len(slice)-1]
This is useful when performance matters more than element order.
Mini Project
Description
Build a small Go program that removes an item from a list of numbers based on a position entered by the user. This project demonstrates safe slice deletion, index validation, and printing updated results. It is a practical version of what many command-line tools do when modifying in-memory data.
Goal
Create a Go program that reads a position, removes that element from a slice safely, and prints the updated slice.
Requirements
- Start with a slice containing at least five integers.
- Read the position to delete from user input.
- Validate that the position is within range.
- Remove the element using idiomatic slice syntax.
- Print the updated slice after deletion.
Keep learning
Related questions
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.
Check if a Value Exists in a Slice in Go
Learn how to check whether a value exists in a slice in Go, and why Go has no Python-style `in` operator for arrays or slices.
Concatenating Slices in Go with append
Learn how to concatenate two slices in Go using append and the ... operator, with examples, pitfalls, and practical usage.