---
title: "فهم نطاق المتغيرات في Golang: المتغيرات المحلية والعامة"
description: "مكان تعريف المتغير يحدد من يستطيع الوصول إليه. جولة عملية في النطاق المحلي والعام في Go — أخطاء الـ shadowing، والمتغيرات العامة عبر الـ packages، ودوال الـ getter، وsync.Once — مع أمثلة جاهزة للتشغيل."
url: https://akemara.com/ar/blog/golang-variable-scope/
lang: ar
author: "أحمد كمال عمارة"
date: 2025-02-12
lastmod: 2025-02-12
section: blog
tags: ["Golang","Go","المتغيرات","هندسة البرمجيات"]
translations:
  en: https://akemara.com/en/blog/golang-variable-scope/
---

# فهم نطاق المتغيرات في Golang: المتغيرات المحلية والعامة

> مكان تعريف المتغير يحدد من يستطيع الوصول إليه. جولة عملية في النطاق المحلي والعام في Go — أخطاء الـ shadowing، والمتغيرات العامة عبر الـ packages، ودوال الـ getter، وsync.Once — مع أمثلة جاهزة للتشغيل.

## مقدمة {#introduction}

في Golang، يحدد نطاق المتغير (Variable Scope) الأماكن التي يمكن الوصول فيها إلى المتغير وتعديله داخل البرنامج. قد يبدو الموضوع للوهلة الأولى من أساسيات المبتدئين — إلى أن تكتشف أن متغيرًا عامًا ظننت أنك حدّثته لم يتغير أصلًا، والسبب كله علامة `:=` واحدة! لذا فإن فهم النطاق **المحلي** والنطاق **العام** أمر جوهري لكتابة كود سهل الصيانة وخالٍ من الأخطاء. وعندما تعمل عبر أكثر من package، فإن التعامل الصحيح مع المتغيرات العامة يضمن لك كودًا معياريًا قابلًا لإعادة الاستخدام.

**سنغطي في هذا المقال:**

- المتغيرات المحلية والعامة في Golang
- تحديث المتغيرات العامة داخل الدوال
- استخدام المتغيرات العامة عبر أكثر من package
- أفضل الممارسات لإدارة المتغيرات العامة

## المتغيرات المحلية والعامة في Golang {#local-vs-global-variables-in-golang}

## المتغيرات المحلية: نطاق الدالة أو الـ Block {#local-variables-functionblock-scope}

يكون المتغير **محليًا (Local)** عندما يُعرَّف **داخل** دالة (Function) أو حلقة تكرار أو block. ولا يمكن الوصول إليه إلا داخل تلك الدالة أو ذلك الـ block تحديدًا، ولا يمكن استخدامه في أي مكان آخر.

### مثال: نطاق المتغير المحلي {#example-local-variable-scope}

```go
package main

import "fmt"

func main() {
    x := 10  // Local variable in main()
    fmt.Println(x) // Accessible within main()

    if true {
        y := 20 // Local to the if block
        fmt.Println(y)
    }

    // fmt.Println(y) // ERROR: y is out of scope here
}
```

- المتغير `x` محلي داخل `main()`.
- المتغير `y` محلي داخل block الـ `if` ولا يمكن الوصول إليه خارجه.

## المتغيرات العامة: نطاق الـ Package {#global-variables-package-scope}

المتغير **العام (Global)** هو المتغير المُعرَّف **خارج أي دالة**، ويمكن الوصول إليه من أي مكان داخل الـ package.

### مثال: متغير عام {#example-global-variable}

```go
package main

import "fmt"

var globalVar = 100 // Global variable

func main() {
    fmt.Println("Before update:", globalVar)
    updateGlobalVar()
    fmt.Println("After update:", globalVar) // Value changed globally
}

func updateGlobalVar() {
    globalVar = 200 // Modifying global variable
}
```

- المتغير `globalVar` مُعرَّف **خارج** أي دالة، ما يجعله متاحًا لكل الدوال داخل الـ package.
- الدالة `updateGlobalVar()` تعدّل قيمة `globalVar`، وينعكس التغيير على مستوى البرنامج كله.

## تحديث متغير عام داخل دالة {#updating-a-global-variable-inside-a-function}

يمكن تحديث المتغيرات العامة مباشرة داخل الدوال — **إلا إذا حجبها** متغير محلي يحمل الاسم نفسه (وهذا ما يُعرف بالـ shadowing).

### مثال: تعديل متغير عام مباشرة {#example-directly-modifying-a-global-variable}

```go
var counter = 0 // Global variable

func increment() {
    counter++ // Modifies the global variable
}

func main() {
    fmt.Println("Before increment:", counter)
    increment()
    fmt.Println("After increment:", counter) // Value updated globally
}
```

## الخطأ الشائع: الـ Shadowing {#common-mistake-variable-shadowing}

من الأخطاء الشائعة **إعادة تعريف** متغير عام باستخدام `:=`، وهو ما يُنشئ متغيرًا محليًا جديدًا بدلًا من تعديل المتغير العام. هذا هو النوع من الأخطاء الذي يبدو وكأنه يعمل: الدالة تطبع القيمة الجديدة، بينما يحتفظ المتغير العام بقيمته القديمة في صمت.

```go
var data = "Global"

func changeData() {
    data := "Local" // Creates a new local variable, doesn't modify the global one
    fmt.Println("Inside function:", data)
}

func main() {
    fmt.Println("Before:", data)
    changeData()
    fmt.Println("After:", data) // Still "Global"
}
```

- الحل: استخدم `data = "Modified Global"` بدلًا من `:=` لتحديث المتغير العام.

## استخدام المتغيرات العامة عبر أكثر من Package {#using-global-variables-across-multiple-packages}

المتغيرات العامة المشتركة بين أكثر من package يجب أن تكون **مُصدَّرة (Exported)** — أي أن يبدأ اسمها بحرف كبير — وأن تُستورد بالشكل الصحيح.

## مثال على هيكل المشروع {#project-structure-example}

```
project/
│── main.go
│── config/
│   ├── config.go
```

## الخطوة 1: تعريف متغير عام داخل package الـ config {#step-1-define-a-global-variable-in-config-package}

أنشئ الملف `config/config.go` وعرّف فيه متغيرًا مُصدَّرًا:

```go
package config

import "fmt"

// Exported global variable (uppercase first letter)
var AppName = "My Awesome App"

func PrintConfig() {
    fmt.Println("App Name:", AppName)
}
```

## الخطوة 2: الوصول إلى المتغير العام من main.go {#step-2-access-the-global-variable-in-maingo}

استورد package الـ `config` واستخدم المتغير العام:

```go
package main

import (
    "fmt"
    "project/config" // Importing the package
)

func main() {
    fmt.Println("Application:", config.AppName) // Accessing global variable
    config.PrintConfig()
}
```

- المتغير `AppName` متاح هنا لأنه مُصدَّر.
- الدالة `config.PrintConfig()` تطبع قيمة المتغير.

## الخطوة 3: تعديل المتغير العام من package آخر {#step-3-modifying-global-variable-from-another-package}

المتغيرات العامة داخل أي package **يمكن تحديثها** من packages أخرى ما دامت مُصدَّرة.

```go
package main

import (
    "fmt"
    "project/config"
)

func main() {
    fmt.Println("Before:", config.AppName)

    // Modifying global variable
    config.AppName = "Updated App Name"

    fmt.Println("After:", config.AppName)
}
```

## منع التعديل باستخدام دوال الـ Getter {#preventing-modification-with-getter-functions}

إذا أردت **حماية متغير عام** من التعديل خارج الـ package الخاص به، اجعله **خاصًا (Private)** ووفّر دالة getter للوصول إليه.

```go
package config

// Unexported variable
var appName = "My Secure App"

// Getter function
func GetAppName() string {
    return appName
}
```

الآن لا يمكن تعديل `appName` من `main.go`، لكن يظل بالإمكان قراءته عبر `config.GetAppName()`.

## استخدام sync.Once للتهيئة {#using-synconce-for-initialization}

استخدم `sync.Once` لضمان أن تهيئة (Initialization) المتغير العام تحدث **مرة واحدة فقط**.

```go
package config

import "sync"

var (
    once    sync.Once
    AppName string
)

func InitConfig() {
    once.Do(func() {
        AppName = "Initialized App Name"
    })
}
```

```go
package main

import (
    "fmt"
    "project/config"
)

func main() {
    config.InitConfig()
    fmt.Println("Application:", config.AppName)
}
```

## أفضل الممارسات للتعامل مع المتغيرات العامة {#best-practices-for-global-variables}

- ✅ **قلّل من المتغيرات العامة**: الإفراط فيها يجعل صيانة الكود أصعب مع الوقت.
- ✅ **استخدم دوال getter/setter**: إذا كان التعديل يجب أن يكون مقيدًا، وفّر دوال بدلًا من كشف المتغير نفسه.
- ✅ **استخدم `sync.Once` للتهيئة**: تجنّب التهيئة المتكررة (وسباقات التهيئة المتزامنة).
- ✅ **تجنّب التبعيات غير الضرورية بين الـ packages**: ضع المتغيرات العامة في packages مخصصة لتفادي الاستيراد الدائري (Circular Imports).

## الخلاصة {#conclusion}

![جدول يلخّص أنواع نطاق المتغيرات في Go: المحلي والعام وعبر الـ packages](https://akemara.com/ar/blog/golang-variable-scope/images/webp/conclusion.webp)

نطاق المتغيرات في Golang يتبع قواعد واضحة: المتغير محلي افتراضيًا، ويصبح متاحًا على مستوى الـ package عندما يُعرَّف في المستوى الأعلى، ولا يُرى عبر الـ packages الأخرى إلا إذا كان مُصدَّرًا.

وبالالتزام بأفضل الممارسات، ستتمكن من كتابة برامج Go **قابلة للتوسع، معيارية، وسهلة الصيانة**. 🚀
