آموزش توابع در گولنگ - راهنمای کامل Function در Go
2025/11/24توابع یکی از مهمترین بخشهای هر زبان برنامهنویسی هستند. در Go، توابع شهروندان درجه یک (first-class citizens) هستند، یعنی میتوانید آنها را به متغیرها assign کنید، به توابع دیگر پاس دهید و از توابع برگردانید.
تعریف تابع
سینتکس پایه:
func functionName(parameters) returnType {
// بدنه تابع
return value
}مثال ساده
package main
import "fmt"
// تابع بدون پارامتر و بازگشت
func sayHello() {
fmt.Println("سلام!")
}
// تابع با پارامتر
func greet(name string) {
fmt.Printf("سلام %s!\n", name)
}
// تابع با پارامتر و بازگشت
func add(a int, b int) int {
return a + b
}
// پارامترهای همنوع - سینتکس کوتاه
func multiply(a, b int) int {
return a * b
}
func main() {
sayHello()
greet("علی")
result := add(5, 3)
fmt.Println("نتیجه:", result)
}چندین مقدار بازگشتی
Go از چندین مقدار بازگشتی پشتیبانی میکند:
package main
import (
"errors"
"fmt"
)
// دو مقدار بازگشتی
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, errors.New("تقسیم بر صفر امکانپذیر نیست")
}
return a / b, nil
}
// مقادیر بازگشتی نامگذاری شده
func getStats(numbers []int) (min, max, sum int) {
if len(numbers) == 0 {
return 0, 0, 0
}
min = numbers[0]
max = numbers[0]
sum = 0
for _, n := range numbers {
if n < min {
min = n
}
if n > max {
max = n
}
sum += n
}
return // بازگشت ضمنی
}
func main() {
// مدیریت خطا
result, err := divide(10, 2)
if err != nil {
fmt.Println("خطا:", err)
} else {
fmt.Println("نتیجه:", result)
}
// نادیده گرفتن یک مقدار با _
_, err = divide(10, 0)
if err != nil {
fmt.Println("خطا:", err)
}
// استفاده از getStats
numbers := []int{5, 2, 8, 1, 9}
min, max, sum := getStats(numbers)
fmt.Printf("min=%d, max=%d, sum=%d\n", min, max, sum)
}Variadic Functions (توابع با پارامتر متغیر)
package main
import "fmt"
// تابع با تعداد پارامتر متغیر
func sum(numbers ...int) int {
total := 0
for _, n := range numbers {
total += n
}
return total
}
// ترکیب پارامتر عادی و variadic
func printf(format string, args ...interface{}) {
fmt.Printf(format, args...)
}
func main() {
// فراخوانی با تعداد مختلف آرگومان
fmt.Println(sum()) // 0
fmt.Println(sum(1)) // 1
fmt.Println(sum(1, 2, 3)) // 6
fmt.Println(sum(1, 2, 3, 4, 5)) // 15
// پاس دادن slice با ...
nums := []int{1, 2, 3, 4, 5}
fmt.Println(sum(nums...)) // 15
}توابع ناشناس (Anonymous Functions)
package main
import "fmt"
func main() {
// تعریف و فراخوانی فوری
func() {
fmt.Println("تابع ناشناس!")
}()
// تعریف و assign به متغیر
greet := func(name string) {
fmt.Printf("سلام %s!\n", name)
}
greet("علی")
// تابع ناشناس با بازگشت
add := func(a, b int) int {
return a + b
}
fmt.Println(add(3, 4))
// پاس دادن تابع به تابع دیگر
numbers := []int{1, 2, 3, 4, 5}
doubled := transform(numbers, func(n int) int {
return n * 2
})
fmt.Println(doubled) // [2 4 6 8 10]
}
func transform(nums []int, fn func(int) int) []int {
result := make([]int, len(nums))
for i, n := range nums {
result[i] = fn(n)
}
return result
}Closure
Closure تابعی است که به متغیرهای خارج از بدنه خود دسترسی دارد:
package main
import "fmt"
// تابعی که تابع برمیگرداند
func counter() func() int {
count := 0
return func() int {
count++
return count
}
}
// تولیدکننده شناسه
func idGenerator(prefix string) func() string {
id := 0
return func() string {
id++
return fmt.Sprintf("%s-%d", prefix, id)
}
}
func main() {
// هر counter مستقل است
c1 := counter()
c2 := counter()
fmt.Println(c1()) // 1
fmt.Println(c1()) // 2
fmt.Println(c1()) // 3
fmt.Println(c2()) // 1 (مستقل از c1)
// تولید شناسه
userID := idGenerator("user")
orderID := idGenerator("order")
fmt.Println(userID()) // user-1
fmt.Println(userID()) // user-2
fmt.Println(orderID()) // order-1
}defer
defer اجرای تابع را به پایان تابع جاری موکول میکند:
package main
import (
"fmt"
"os"
)
func main() {
// ترتیب اجرا: LIFO (آخرین، اول)
defer fmt.Println("1")
defer fmt.Println("2")
defer fmt.Println("3")
fmt.Println("شروع")
// خروجی: شروع، 3، 2، 1
// کاربرد عملی: بستن فایل
readFile()
}
func readFile() {
file, err := os.Open("test.txt")
if err != nil {
fmt.Println("خطا:", err)
return
}
defer file.Close() // تضمین بسته شدن فایل
// خواندن و پردازش فایل...
fmt.Println("فایل باز شد")
}
// defer با مقادیر
func deferWithValues() {
x := 10
defer fmt.Println("x =", x) // x = 10 (مقدار در زمان defer)
x = 20
fmt.Println("x در پایان:", x) // x در پایان: 20
}
// defer برای زمانسنجی
func measureTime() func() {
start := time.Now()
return func() {
fmt.Printf("زمان اجرا: %v\n", time.Since(start))
}
}
func slowFunction() {
defer measureTime()()
// کار زمانبر
time.Sleep(2 * time.Second)
}متدها (Methods)
متد تابعی است که به یک type متصل شده:
package main
import (
"fmt"
"math"
)
// تعریف struct
type Rectangle struct {
Width float64
Height float64
}
type Circle struct {
Radius float64
}
// متد با value receiver
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
func (r Rectangle) Perimeter() float64 {
return 2 * (r.Width + r.Height)
}
// متد با pointer receiver (میتواند struct را تغییر دهد)
func (r *Rectangle) Scale(factor float64) {
r.Width *= factor
r.Height *= factor
}
// متد برای Circle
func (c Circle) Area() float64 {
return math.Pi * c.Radius * c.Radius
}
func main() {
rect := Rectangle{Width: 10, Height: 5}
fmt.Printf("مساحت: %.2f\n", rect.Area())
fmt.Printf("محیط: %.2f\n", rect.Perimeter())
// تغییر با pointer receiver
rect.Scale(2)
fmt.Printf("مساحت جدید: %.2f\n", rect.Area())
circle := Circle{Radius: 5}
fmt.Printf("مساحت دایره: %.2f\n", circle.Area())
}Interface
package main
import (
"fmt"
"math"
)
// تعریف interface
type Shape interface {
Area() float64
Perimeter() float64
}
type Rectangle struct {
Width, Height float64
}
type Circle struct {
Radius float64
}
// پیادهسازی interface برای Rectangle
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
func (r Rectangle) Perimeter() float64 {
return 2 * (r.Width + r.Height)
}
// پیادهسازی interface برای Circle
func (c Circle) Area() float64 {
return math.Pi * c.Radius * c.Radius
}
func (c Circle) Perimeter() float64 {
return 2 * math.Pi * c.Radius
}
// تابع که از interface استفاده میکند
func printShapeInfo(s Shape) {
fmt.Printf("مساحت: %.2f\n", s.Area())
fmt.Printf("محیط: %.2f\n", s.Perimeter())
}
func main() {
rect := Rectangle{Width: 10, Height: 5}
circle := Circle{Radius: 7}
printShapeInfo(rect)
fmt.Println("---")
printShapeInfo(circle)
// slice از interface
shapes := []Shape{rect, circle}
for _, shape := range shapes {
fmt.Printf("مساحت: %.2f\n", shape.Area())
}
}Higher-Order Functions
توابعی که تابع میگیرند یا تابع برمیگردانند:
package main
import "fmt"
// Map
func Map[T, U any](slice []T, fn func(T) U) []U {
result := make([]U, len(slice))
for i, v := range slice {
result[i] = fn(v)
}
return result
}
// Filter
func Filter[T any](slice []T, fn func(T) bool) []T {
var result []T
for _, v := range slice {
if fn(v) {
result = append(result, v)
}
}
return result
}
// Reduce
func Reduce[T, U any](slice []T, initial U, fn func(U, T) U) U {
result := initial
for _, v := range slice {
result = fn(result, v)
}
return result
}
func main() {
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
// دوبرابر کردن
doubled := Map(numbers, func(n int) int {
return n * 2
})
fmt.Println("Doubled:", doubled)
// فیلتر زوجها
evens := Filter(numbers, func(n int) bool {
return n%2 == 0
})
fmt.Println("Evens:", evens)
// مجموع
sum := Reduce(numbers, 0, func(acc, n int) int {
return acc + n
})
fmt.Println("Sum:", sum)
}جدول خلاصه
| مفهوم | سینتکس | کاربرد |
|---|---|---|
| تابع ساده | func name() {} |
عملیات پایه |
| با پارامتر | func name(a int) {} |
ورودی |
| با بازگشت | func name() int {} |
خروجی |
| چند بازگشت | func name() (int, error) {} |
خروجی + خطا |
| Variadic | func name(args ...int) {} |
تعداد متغیر |
| ناشناس | func() {}() |
inline |
| Closure | func() func() {} |
دسترسی به scope بیرونی |
| defer | defer fn() |
اجرای تأخیری |
| Method | func (r T) name() {} |
متصل به type |