OSGo.005 introduces functions as named, reusable units of Go code. The central language features are typed parameters, multiple returned values, variadic inputs, and explicit error results. A function can perform a small, testable operation and report whether its result is valid. Understanding the contract between a caller and a function makes programs easier to read, test, and troubleshoot without relying on global variables or unexplained failure values.
OSGo.005 advances OSGo.004 on control flow. Earlier operators and expressions, variables and types, and toolchain fundamentals are prerequisites. The lesson uses the official Go Tour’s introduction to functions, the Go language specification, and the Go team’s published tutorial on error results.
Learning Objectives and Prerequisites
- Read and write a typed function declaration with named input parameters.
- Explain that Go arguments are passed by value, while some values contain references to underlying data.
- Use functions that return one value, multiple values, and an explicit error.
- Use a variadic parameter ending in
...Tand expand a slice with...at a call site. - Distinguish named result parameters from a recommended explicit return.
- Run a complete example, unit tests, and static analysis without external dependencies.
- Explain why ordinary data-validation failures should be returned as errors rather than hidden in a magic output.
Requirements: a working Go toolchain (the local examples were run with go1.23.2 linux/amd64), a text editor, and a terminal. Current supported Go releases may differ; check the official downloads page before installing. No third-party modules, credentials, network access, or elevated privileges are needed for the exercises.

Functions Package Behavior into Named Operations
A Go function declaration begins with func, followed by the function name, a parenthesized parameter list, an optional return type or result list, and a body. For example, func double(n int) int { return n * 2 } accepts an integer and returns another integer. A declaration can group adjacent parameters of the same type, as in func add(a, b int) int. The caller supplies values in the declared order, and the compiler checks their types.
Go evaluates function arguments and passes values. Copying an int gives the callee an independent integer. Copying a slice value copies its slice header rather than duplicating all underlying elements; both values can refer to the same backing array. Passing a pointer also copies the pointer value, not the pointed-to object. Those distinctions are explained by the official Go FAQ and are important when functions modify data.
Parameter names are local to their function. A function must not assume that a caller’s local variable exists inside it. Return values provide an explicit path for sending computed results back to the caller. As programs grow, carefully named functions make implementation details easier to replace while preserving a stable external contract.
Net Ninja, “Go (Golang) Tutorial #10 — Multiple Return Values,” May 28, 2021. Public educational programming tutorial; the title, channel and video ID were verified before embedding. This is a community instructor, not an official Go project release.
Multiple Results and Named Result Parameters
Go lets a function return more than one result without constructing a separate struct or using an output pointer. The official Go Tour’s multiple-results exercise demonstrates a function returning two strings. A common production signature returns a value plus an error, making both the result and its validity visible to the caller. By convention, successful operations return a nil error, and failed operations return an informative non-nil error.
Result parameters may be named, such as func minMax(values []int) (minimum, maximum int, err error). They begin with their type’s zero value and are local variables within the function. A bare return is permitted when all results are named, but the official guidance recommends explicit results for clarity, especially as functions grow. The example below uses named results to clarify meaning while still explicitly returning the values.
When a function cannot satisfy its contract, return an error rather than an arbitrary number whose meaning is ambiguous. The average function must reject an empty input because the requested average would require dividing by zero. minMax similarly rejects an empty slice because no minimum or maximum exists. Both return typed results plus errors; the caller examines err before using a result.
Variadic Parameters and Slice Expansion
A final function parameter written as values ...float64 accepts zero or more float64 arguments. Inside the function, values behaves like a slice. Variadic parameters must be last. A preexisting slice can be passed as individual arguments using an ellipsis at the call site, such as measurements := []int{2, 6, 8} followed by countAbove(5, measurements...). The function still receives ordinary typed values, and its logic must decide whether empty input is valid.
Go does not require a function’s variadic input to contain any elements. In the example, countAbove returns zero for an empty value list, which is meaningful. average returns an error for an empty list, because a mean is undefined. Function contracts, not the ellipsis syntax alone, define correct error behavior.
Complete Executable Program
The following source combines single and multiple returned results, a variadic parameter, named results, explicit error checks, and a controlled fallback for invalid input. No external dependencies are used. Place it in a file named main.go. The results presented below were obtained with the locally installed Go 1.23.2 compiler and standard library.
package main
import (
"errors"
"fmt"
)
// average accepts zero or more float64 arguments and returns a value or error.
func average(values ...float64) (float64, error) {
if len(values) == 0 {
return 0, errors.New("at least one value is required")
}
var sum float64
for _, value := range values {
sum += value
}
return sum / float64(len(values)), nil
}
// minMax returns two results and an error; named results aid documentation.
func minMax(values []int) (minimum, maximum int, err error) {
if len(values) == 0 {
return 0, 0, errors.New("cannot inspect an empty slice")
}
minimum, maximum = values[0], values[0]
for _, v := range values[1:] {
if v < minimum {
minimum = v
}
if v > maximum {
maximum = v
}
}
return minimum, maximum, nil
}
// countAbove places the variadic parameter last, as Go requires.
func countAbove(threshold int, values ...int) int {
count := 0
for _, v := range values {
if v > threshold {
count++
}
}
return count
}
func main() {
mean, err := average(10, 20, 30)
if err != nil {
fmt.Println("average error:", err)
return
}
fmt.Printf("average: %.2f\n", mean)
lo, hi, err := minMax([]int{9, 2, 15, 7})
if err != nil {
fmt.Println("range error:", err)
return
}
fmt.Printf("minimum: %d, maximum: %d\n", lo, hi)
fmt.Printf("above five: %d\n", countAbove(5, 2, 6, 8, 1))
if _, err := average(); err != nil {
fmt.Println("empty input:", err)
}
}
To run it from a new directory, create a module and execute the program. The module name is an example, not a network dependency:
go mod init example.com/osgo005
go run .
Locally observed standard output after running the program:
average: 20.00
minimum: 2, maximum: 15
above five: 2
empty input: at least one value is required
The average function evaluates (10 + 20 + 30) ÷ 3 = 20.00. minMax identifies 2 and 15 from a four-value slice. countAbove counts the elements 6 and 8, which are strictly greater than five. The final call demonstrates normal error handling for an empty input; no panic or stack trace is required.
Unit Tests, Go Vet, and Reproducible Results
Place the following tests alongside main.go in a file named main_test.go. Tests check successful inputs, errors on empty input, and five variadic threshold cases. The values are fully synthetic educational inputs, not measured service traffic or production telemetry.
package main
import "testing"
func TestAverage(t *testing.T) {
got, err := average(10, 20, 30)
if err != nil || got != 20 {
t.Fatalf("average = %v, %v; want 20, nil", got, err)
}
if _, err := average(); err == nil {
t.Fatal("average without values should return an error")
}
}
func TestMinMax(t *testing.T) {
low, high, err := minMax([]int{9, 2, 15, 7})
if err != nil || low != 2 || high != 15 {
t.Fatalf("minMax = %d, %d, %v; want 2, 15, nil", low, high, err)
}
if _, _, err := minMax(nil); err == nil {
t.Fatal("minMax empty input should return an error")
}
}
func TestCountAbove(t *testing.T) {
data := []int{2, 6, 8, 12, 18}
for _, tc := range []struct{ threshold, want int }{
{0, 5}, {5, 4}, {10, 2}, {15, 1}, {20, 0},
} {
got := countAbove(tc.threshold, data...)
if got != tc.want {
t.Errorf("countAbove(%d) = %d; want %d", tc.threshold, got, tc.want)
}
}
}
Run go test -v ./... and go vet ./.... Both commands completed successfully in the local Go 1.23.2 environment. The three test groups were TestAverage, TestMinMax, and TestCountAbove. A passing result verifies the listed cases only; it does not guarantee correctness for all possible floating-point values, untrusted input, or future modifications.
go test -v ./...
go vet ./...
A Chart Tied to the Actual Test Cases
The last test evaluates countAbove on values [2, 6, 8, 12, 18]. For thresholds 0, 5, 10, 15, and 20, the expected counts are 5, 4, 2, 1, and 0. All five assertions passed. The chart represents these deliberately chosen function test inputs and outputs. It is not a benchmark, external dataset, or measurement of Go program performance.

TestCountAbove unit-test cases. Data are synthetic and asserted in the included source. No performance or runtime measurements are claimed.Changing the threshold tests an important detail of the function contract: the comparison is v > threshold, not v >= threshold. A value exactly equal to the threshold must not be counted. Boundary cases such as equality, an empty slice, negative values, and repeated values are valuable additions to a larger test suite.
freeCodeCamp.org, “Learn Go Programming — Golang Tutorial for Beginners,” June 20, 2019. Verified public nonprofit educational course by Michael Van Sickle. The functions section begins around 4:21:30; use that chapter rather than treating the entire six-hour course as a focused lesson on functions.
Troubleshooting and Defensive Contracts
If a caller receives a compile error such as not enough arguments in call, compare the argument list with the function declaration and distinguish required parameters from a final variadic parameter. A mismatch such as passing []int directly to ...int requires a slice expansion where appropriate: items.... When Go reports a wrong number of returned values, check whether the function supplies one result, a tuple-like result list, or a value-plus-error pair.
For an unexpected result, inspect the loop comparison and the values passed to it. For example, countAbove(5, 5) is zero because the comparison is strictly greater. When testing floating-point functions, use a defined tolerance for results that cannot be represented exactly in binary; the present average uses exact small integer-valued floats, making a direct equality check acceptable for the stated case. Do not silently extend that assumption to every decimal input.
Use error values to describe predictable invalid input. Avoid a panic for routine validation failures, and avoid discarding errors with the blank identifier merely to make a program compile. For code handling external measurements, add validation for NaN, infinities, out-of-range inputs, and limits on the number of elements. A variadic function receiving a very large slice may also create work and memory pressure if the application blindly trusts caller-supplied data.
Security considerations include protecting secrets in function parameters, avoiding unbounded allocations, returning errors that inform the caller without leaking sensitive paths or tokens, and not logging confidential input values. The present standalone example does not perform network access, write files, or require additional privileges, but those constraints must be revisited when adapting it to real service or monitoring software.
Guided Practice Exercises
- Write a
square(n int) intfunction and call it with 4 and -3. Predict the returned results. - Modify
averageto acceptvalues := []float64{10, 20, 30}usingaverage(values...). Explain what the final ellipsis does. - Call
minMax(nil)and confirm the caller handles the returned error before displaying a minimum or maximum. - Extend the unit tests with
countAbove(5, 5)and a negative threshold; explain strict versus non-strict comparison. - Add a new
sum(values ...int) intfunction. Decide whether the empty argument list should produce zero or an error, and justify the contract. - Use the official Go Tour to compare named result parameters with a function that returns values explicitly. Keep the resulting code readable.
- Run
go test -v ./...after each change and document the compiler and test version rather than assuming all tools behave identically across releases.
Knowledge Check and Answers
- How are Go function parameters declared? With names and types in parentheses after the function name.
- Can a Go function return two values? Yes. The declaration supplies a parenthesized result list, and the caller can assign the returned values to two variables.
- What is the conventional second result for a failing operation? An
error, withnilindicating success. - Are Go function arguments passed by value? Yes. Some copied values contain references to shared underlying objects, such as slice descriptors and pointers.
- Where must a variadic parameter appear? Last in the function’s parameter list.
- What does
values...do at a variadic call site? It passes a compatible slice’s elements as variadic arguments. - What does
average()return in the example? The zero value with a non-nil error explaining that at least one value is required. - What is the main output for
average(10, 20, 30)? 20.00, formatted to two decimal places. - Why does
countAbove(5, 5)return zero? Because the test is>, not>=. - Did passing local tests prove every possible input is safe? No. Only the documented cases were executed; input and security requirements must be extended for production use.
Primary Documentation and Educational References
A Tour of Go — Functions; A Tour of Go — Multiple Results; Go Language Specification; Effective Go; Go Tutorial — Return and Handle an Error; Go FAQ — Pass by Value; Go Brand and Gopher Attribution; and the verified Net Ninja and freeCodeCamp.org educational videos embedded above. The Go project website is the primary source for syntax and language semantics.
Conclusion
Functions provide Go programs with reusable operations and explicit contracts. Typed inputs, multiple return values, variadic parameters, and returned errors allow a caller to understand not only a computed result but also whether the operation succeeded. Tested examples and carefully explained error paths build a foundation for methods, interfaces, packages, and more complex Go systems later in the curriculum.
Editor’s Note: OSGo.005 follows verified OSGo.004 and the published OSRust.007 lesson in the broader subject rotation. The 1200 × 630 featured image is original AI-generated editorial artwork showing a fictional mid-career male Go instructor; the preceding Rust lesson portrayed an older female mentor. The Go Gopher is genuine official mascot artwork by Renée French, credited under CC BY 4.0. The chart plots synthetic input values whose exact counts passed local Go tests. The embedded videos are authentic educational tutorials from Net Ninja and freeCodeCamp.org, not recordings made for this publication. The source and tests were executed with go1.23.2 on Linux, and go vet completed successfully. No video playback, network service, or production software workload is represented as tested without independent evidence.

To donate using a mobile wallet, display the original QR on another device or use your wallet’s supported saved-image scanner. Verify the recipient and the 5,000-satoshi amount before sending funds.
We volunteer daily to ensure the information on this platform is Verifiably True. If you would like to support the research, please scan the QR code.
BitcoinVersus.Tech presents open educational programming material and does not provide a production deployment or security certification. Review official project documentation and test code in the intended environment.

Leave a Reply