Preface: Why is this question so popular?
\n\nIf you've ever written even a couple of lines of code in Go, you've undoubtedly encountered slices. They are a flexible, powerful, and perhaps the most used data structure in the language. And, as often happens, the simplest question — "how do I get the last element?" — turns out to be one of the most frequent on Stack Overflow. Thousands of developers, from beginners to pros, search for this information. Why?
\n\nFirstly, Go's syntax is concise, and intuition suggests: "if there is a first element (slice[0]), then there must be a last one." But Go doesn't have a .Last() method or slice[-1] like Python. Secondly, pitfalls with empty slices and index out of bounds errors catch even experienced programmers.
In this tutorial, we'll cover all the ways to get the last element of a slice in Go, from classic to advanced, with code examples and analysis of typical mistakes. Let's go!
\n\n1. The Classic Way: len(slice) — 1
\n\nThe most direct and frequently used method is to access the element by index equal to the slice length minus one. In Go, indexing starts from zero, so if you have a slice of 5 elements, their indices are: 0, 1, 2, 3, 4.
\n\npackage main\n\nimport "fmt"\n\nfunc main() {\n numbers := []int{10, 20, 30, 40, 50}\n last := numbers[len(numbers)-1]\n fmt.Println(last) // Output: 50\n}\n\n\nIt works perfectly. But there is one important nuance: an empty slice. If you try to call len(emptySlice)-1 on an empty slice, the length will be 0, the index will become -1, and the program will panic with index out of range.
var empty []int\n// last := empty[len(empty)-1] // PANIC: runtime error: index out of range [-1]\n\n\nConclusion: This method is great when you are sure the slice is not empty. Otherwise, read on.
\n\n2. The Safe Way with Length Check
\n\nTo avoid a panic, simply check the slice length before accessing the last element. This is an idiomatic and safe approach that should be used in production code.
\n\nfunc GetLastElement(s []int) (int, bool) {\n if len(s) == 0 {\n return 0, false // or another default value\n }\n return s[len(s)-1], true\n}\n\n\nHere's an example using it in the main function:
\n\npackage main\n\nimport "fmt"\n\nfunc main() {\n slice1 := []string{"Go", "Python", "Rust"}\n slice2 := []string{}\n\n if last, ok := safeLast(slice1); ok {\n fmt.Println("Last element of slice1:", last) // Rust\n }\n\n if _, ok := safeLast(slice2); !ok {\n fmt.Println("slice2 is empty, no last element")\n }\n}\n\nfunc safeLast(s []string) (string, bool) {\n if len(s) == 0 {\n return "", false\n }\n return s[len(s)-1], true\n}\n\n\nWhy is this good? The function returns two values: the element itself and a boolean success flag. This is a standard Go idiom (remember reading from a map: value, ok := myMap["key"]). The code becomes readable and reliable.
3. Using Reflection (for Generality)
\n\nSometimes you need to write a function that works with any slice type. The reflect package comes to the rescue. However, I warn you: this is slower and more complex, so only use it if you really need to.
package main\n\nimport (\n "fmt"\n "reflect"\n)\n\nfunc LastElement(slice interface{}) (interface{}, bool) {\n v := reflect.ValueOf(slice)\n if v.Kind() != reflect.Slice {\n return nil, false\n }\n if v.Len() == 0 {\n return nil, false\n }\n return v.Index(v.Len() - 1).Interface(), true\n}\n\nfunc main() {\n ints := []int{1, 2, 3}\n strs := []string{"a", "b", "c"}\n\n if last, ok := LastElement(ints); ok {\n fmt