پرش به محتوای اصلی

فاز ۰: راه‌اندازی و طرز فکر Go · درس ۱

نصب toolchain و اولین برنامه

Go را نصب می‌کنید، اولین برنامه را می‌نویسید و می‌بینید چرا خروجی آن یک فایل اجرایی مستقل است، نه کدی که به مفسر نیاز دارد.

مقدماتیزمان پیشنهادی: ۱ ساعتزمان مطالعه: ۱۴ دقیقه
در این صفحه

هدف

در پایان این درس:

  • Go روی سیستم شما نصب است و می‌دانید هر بخش آن کجا قرار می‌گیرد.
  • اولین برنامه را با go run اجرا و با go build به فایل اجرایی تبدیل کرده‌اید.
  • می‌دانید چرا تحویل یک سرویس Go به سرور با تحویل یک پروژهٔ Django فرق اساسی دارد.

در Django برای اجرای پروژه روی سرور به مفسر Python، یک محیط مجازی و همهٔ بسته‌های نصب‌شده نیاز دارید. در Go خروجی کار یک فایل است که آن را کپی و اجرا می‌کنید. همین تفاوت، شکل Dockerfile، سرعت بالا آمدن سرویس و روش انتشار را عوض می‌کند.

مفهوم

toolchain چیست

toolchain (زنجیرهٔ ابزار) مجموعه‌ای است که با نصب Go می‌گیرید: کامپایلر، linker (پیونددهنده)، کتابخانهٔ استاندارد و دستور go که همهٔ این‌ها را هدایت می‌کند. برخلاف Python که برای قالب‌بندی، تست و مدیریت بسته به ابزارهای جدا مثل ruff، pytest و uv نیاز دارید، در Go همهٔ این کارها زیردستورهای همان go هستند.

نصب

  1. دانلود و نصب

    بستهٔ سیستم‌عامل خودتان را از go.dev/dl بگیرید. در macOS می‌توانید از Homebrew هم استفاده کنید. در Windows پیشنهاد این مسیر آموزشی کار داخل WSL است.

    Bash
    brew install go

    برای این مخزن هر نسخه از 1.21 به بعد کافی است، چون خود Go نسخهٔ دقیق پروژه را دانلود می‌کند. دلیلش را در ادامه می‌بینید.

  2. بررسی نصب

    Bash
    go version
  3. دیدن محل پوشه‌ها

    Bash
    go env GOROOT GOPATH GOMODCACHE GOCACHE
bash
$ go versiongo version go1.27.4 linux/amd64$ go env GOPATH GOMODCACHE GOCACHE/home/you/go/home/you/go/pkg/mod/home/you/.cache/go-build

هر پوشه چه کاری می‌کند

متغیرمحتوانزدیک‌ترین معادل در Python
GOROOTخود toolchain و کتابخانهٔ استانداردمحل نصب مفسر و Lib
GOPATHپوشهٔ کاری Go؛ پیش‌فرض go در پوشهٔ خانهمعادل دقیق ندارد
GOMODCACHEبسته‌های دانلودشده، مشترک بین همهٔ پروژه‌هاcache سراسری uv
GOCACHEنتیجهٔ کامپایل هر package برای استفادهٔ دوباره__pycache__
GOBINمحل نصب ابزارهایی که با go install می‌سازیدپوشهٔ bin محیط مجازی

نکتهٔ مهم برای کسی که از Python می‌آید: در Go محیط مجازی وجود ندارد و لازم هم نیست. بسته‌ها یک بار در GOMODCACHE ذخیره می‌شوند و هر پروژه در فایل go.mod خودش می‌گوید کدام نسخه را می‌خواهد. دو پروژه با دو نسخهٔ متفاوت از یک بسته هیچ تداخلی ندارند.

نسخهٔ Go هر پروژه در خود پروژه قفل می‌شود

فایل go.mod این مخزن را ببینید:

go.modGo
module github.com/alifreeguy/go-for-python-developers/code/go

go 1.27.0

toolchain go1.27.4

خط go حداقل نسخهٔ زبان را می‌گوید و خط toolchain نسخهٔ دقیق ابزار را. اگر Go نصب‌شدهٔ شما قدیمی‌تر باشد، دستور go نسخهٔ خواسته‌شده را خودش دانلود و همان را اجرا می‌کند. این رفتار را متغیر GOTOOLCHAIN کنترل می‌کند که پیش‌فرض آن auto است. نتیجه این است که همهٔ اعضای تیم و CI دقیقاً با یک نسخه کار می‌کنند، بدون ابزار جدایی مثل pyenv.

کد Go و معادل Python

ساده‌ترین برنامه در دو زبان:

main.goGo
package main

import "fmt"

func main() {
	fmt.Println("سلام، دنیا!")
}

سه چیز در نسخهٔ Go اجباری است و در Python نیست:

  1. هر فایل با package شروع می‌شود. برنامهٔ اجرایی باید در package main باشد.
  2. هر چیزی که استفاده می‌کنید باید import شده باشد و هر چیزی که import می‌کنید باید استفاده شود.
  3. نقطهٔ شروع برنامه تابع main است. کد سطح بالای فایل، آن‌طور که در Python می‌نویسید، وجود ندارد.

اجرا:

bash
$ cd code/go$ go run ./phase00/l01_installation/examples/helloسلام، دنیا!

حالا یک مثال کمی واقعی‌تر که آرگومان خط فرمان می‌گیرد و اطلاعات محیط را چاپ می‌کند:

main.goGo
package main

import (
	"fmt"
	"os"
	"runtime"
)

func greeting(name string) string {
	if name == "" {
		name = "دنیا"
	}
	return fmt.Sprintf("سلام، %s!", name)
}

func main() {
	name := ""
	if len(os.Args) > 1 {
		name = os.Args[1]
	}

	fmt.Println(greeting(name))
	fmt.Printf("%s on %s/%s\n", runtime.Version(), runtime.GOOS, runtime.GOARCH)
}
bash
$ go run ./phase00/l01_installation/examples/greet گوفرسلام، گوفر!go1.27.4 on linux/amd64$ go build -o greet ./phase00/l01_installation/examples/greet$ ./greetسلام، دنیا!go1.27.4 on linux/amd64

دستور go build یک فایل اجرایی به نام greet ساخت. این فایل را می‌توانید روی هر سیستم Linux با همان معماری کپی و اجرا کنید، حتی اگر Go روی آن نصب نباشد.

مقایسهٔ کنار هم

موضوعGoPython
مدل اجراکامپایل به کد ماشین پیش از اجراتبدیل به bytecode و اجرا در مفسر
آنچه به سرور می‌رودیک فایل اجراییکد منبع، مفسر و بسته‌ها
جداسازی وابستگی‌هاgo.mod در هر پروژه و cache مشترکمحیط مجازی برای هر پروژه
قفل نسخهٔ زبانخط toolchain در go.mod.python-version و ابزار جدا
نقطهٔ شروعتابع main در package mainاجرای فایل از بالا به پایین
import بدون استفادهخطای کامپایلمجاز؛ فقط linter هشدار می‌دهد
قالب‌بندی کدgofmt، بدون تنظیم و یکسان برای همهruff یا black با تنظیم‌های پروژه
محیط تعاملینداردREPL و notebook
کشف خطای نوعهنگام buildهنگام اجرا، یا با mypy پیش از آن
از نوشتن کد تا اجرا روی سرور

زیر کاپوت

در حال رسم نمودار…

در Go دستور go build این کارها را می‌کند:

  1. هر package را جدا کامپایل می‌کند: تجزیهٔ کد، بررسی نوع‌ها، بهینه‌سازی و تولید کد ماشین.
  2. نتیجهٔ هر package را در GOCACHE نگه می‌دارد. اگر کد عوض نشده باشد، دفعهٔ بعد دوباره کامپایل نمی‌شود.
  3. linker همهٔ packageها را با runtime خود Go در یک فایل می‌گذارد. runtime شامل زمان‌بند goroutineها و garbage collector است.

دستور go run همین کار را می‌کند، فایل اجرایی را در یک پوشهٔ موقت می‌سازد، اجرا می‌کند و بعد دور می‌اندازد.

چون runtime داخل فایل است، حتی برنامهٔ چاپ یک خط هم کوچک نیست. روی linux/amd64 با Go 1.27.4 فایل برنامهٔ hello حدود ۲٫۴ مگابایت شد و با حذف اطلاعات اشکال‌زدایی حدود ۱٫۵ مگابایت:

bash
$ go build -o hello ./phase00/l01_installation/examples/hello$ ls -l hello-rwxr-xr-x 1 you you 2354953 hello$ go build -trimpath -ldflags="-s -w" -o hello ./phase00/l01_installation/examples/hello$ ls -l hello-rwxr-xr-x 1 you you 1507488 hello

در CPython مفسر کد منبع را به bytecode تبدیل می‌کند و یک حلقهٔ ارزیابی آن bytecode را دستور به دستور اجرا می‌کند. bytecode ماژول‌هایی که import می‌شوند در پوشهٔ __pycache__ ذخیره می‌شود، ولی برای اسکریپت اصلی ذخیره نمی‌شود. در هر حال مفسر باید هنگام اجرا حاضر باشد.

پیامد عملی: خطاهایی مثل نام اشتباه یک تابع یا ناسازگاری نوع در Go پیش از اجرا گرفته می‌شوند. در Python همان خطا تا وقتی آن خط اجرا نشود پنهان می‌ماند، مگر اینکه mypy یا تست آن را پیدا کند.

اشتباه‌های رایج

نکته‌های Senior

تمرین‌ها

کد شروع همهٔ تمرین‌ها در code/go/phase00/l01_installation/exercises/exercise.go و code/python/phase00/l01_installation/exercises/exercise.py است. همان فایل‌ها را کامل کنید و تست‌ها را اجرا کنید.

تمرین: سلام با نام دلخواه

GoPythonEasy

تابعی بنویسید که یک نام بگیرد و متن خوشامد برگرداند. اگر نام خالی بود، به‌جای آن واژهٔ «دنیا» را بگذارید. خروجی برای نام خالی باید دقیقاً سلام، دنیا! باشد.

کد شروع

exercise.goGo
func Greeting(name string) string {
	return ""
}
اجرای تست‌ها:make exercise PHASE=00 LESSON=01

تمرین: اطلاعات محیط اجرا

GoPythonMedium

تابعی بنویسید که نسخهٔ زبان، سیستم‌عامل و معماری را در یک رشته برگرداند. در Go قالب خروجی go1.27.4 linux/amd64 است و مقدارها را از بستهٔ runtime بگیرید. در Python قالب Python 3.14.6 linux/x86_64 است و از platform و sys استفاده کنید.

کد شروع

exercise.goGo
func BuildInfo() string {
	return ""
}
اجرای تست‌ها:make exercise PHASE=00 LESSON=01

تمرین: خواندن نسخه از go.mod

GoHard

تابعی بنویسید که متن یک فایل go.mod را بگیرد و نسخهٔ toolchain آن را برگرداند. قاعده‌ها:

  • اگر خط toolchain وجود دارد، نسخهٔ آن بدون پیشوند go برگردد.
  • وگرنه نسخهٔ خط go برگردد.
  • اگر هیچ‌کدام نبود، مقدار دوم بازگشتی false باشد.
  • فاصله‌های اضافه و توضیح انتهای خط نباید نتیجه را خراب کنند.

این تمرین از چیزهایی استفاده می‌کند که هنوز درسشان نرسیده است: حلقه، switch و بستهٔ strings. با تجربهٔ Python می‌توانید از روی مستندات go doc strings.Fields پیش بروید.

کد شروع

exercise.goGo
func ToolchainVersion(goMod string) (string, bool) {
	return "", false
}
اجرای تست‌ها:make exercise PHASE=00 LESSON=01

تمرین: تزریق نسخه هنگام build

GoSenior Challenge

در فایل تمرین متغیر version با مقدار dev تعریف شده است. دو تابع را کامل کنید: Version همان مقدار را برمی‌گرداند و FullVersion آن را با خروجی BuildInfo در قالب dev (go1.27.4 linux/amd64) ترکیب می‌کند.

سپس بدون تغییر کد، کاری کنید که Version مقدار 1.4.0 برگرداند. راهنما: پرچم -ldflags و گزینهٔ -X آن. در پایان توضیح دهید چرا این روش از نوشتن نسخه در یک فایل پیکربندی بهتر است.

کد شروع

exercise.goGo
func Version() string {
	return ""
}

func FullVersion() string {
	return ""
}
اجرای تست‌ها:make exercise PHASE=00 LESSON=01

آزمون

آزمون

۰ از ۷ پاسخ داده شده
  1. ۱.دستور go run . دقیقاً چه می‌کند؟

  2. ۲.اگر بستهٔ os را import کنید ولی از آن استفاده نکنید چه می‌شود؟

  3. ۳.خط toolchain go1.27.4 در go.mod چه نقشی دارد؟

  4. ۴.چرا در Go به محیط مجازی نیاز نیست؟

  5. ۵.چرا فایل اجرایی یک برنامهٔ یک‌خطی حدود ۲ مگابایت است؟

  6. ۶.کدام دستور خروجی Windows را روی Linux می‌سازد؟

  7. ۷.متغیر GOCACHE به چه چیزی اشاره می‌کند؟

به همهٔ پرسش‌ها پاسخ دهید تا نتیجه را ببینید.

خلاصه و چک‌لیست

  • Go کد را پیش از اجرا به کد ماشین کامپایل می‌کند و خروجی یک فایل اجرایی است که runtime را درون خود دارد.
  • همهٔ ابزارها زیردستورهای go هستند: go run، go build، go test، go fmt و go vet.
  • محیط مجازی وجود ندارد؛ go.mod هر پروژه نسخه‌ها را مشخص می‌کند و cache مشترک است.
  • خط toolchain نسخهٔ دقیق ابزار را برای همهٔ تیم یکسان می‌کند.
  • import و متغیر بدون استفاده خطای کامپایل است.

پیش از رفتن به درس بعد مطمئن شوید:

  • go version نسخه را چاپ می‌کند.
  • برنامهٔ hello را هم با go run و هم با go build اجرا کرده‌اید.
  • می‌توانید بگویید GOROOT، GOMODCACHE و GOCACHE هر کدام چه چیزی نگه می‌دارند.
  • تست‌های این درس با make exercise PHASE=00 LESSON=01 سبز است.

پیام commit پیشنهادی

Text
feat(phase00): add lesson 01 installation and first program

این درس را تمام کردید؟

پیشرفت شما فقط در همین مرورگر ذخیره می‌شود.

ویرایش این صفحه در GitHub