سطر الأوامر

أوامر Go تحتوي على مجموعة كاملة من سلسلة الأدوات، هذه الأوامر تغطي التوثيق، التنسيق، فحص الكود، التجميع، الاختبار، إدارة التبعيات وغيرها من الجوانب، يمكن القول أنها تتعلق بجميع جوانب تطوير Go.
bug الإبلاغ عن الأخطاء
build تجميع الحزم والتبعيات
clean مسح الملفات الكائنة
doc عرض التوثيق في الكود المصدري
env عرض معلومات متغيرات بيئة Go
fix إصلاح مشاكل التوافق مع API الناتجة عن تغييرات إصدار go
fmt تنسيق الكود المصدري
generate توليد الكود
get إضافة التبعيات
install تثبيت وتجميع الحزم
list أمر قائمة الحزم/الوحدات
mod أمر صيانة الوحدات
work أمر صيانة مساحة العمل
run تجميع وتشغيل
test اختبار
tool تشغيل أداة go المحددة
version عرض معلومات إصدار go
vet فحص وإخراج المشاكل المحتملة في الكود المصدريهذه المقالة هي مجرد وصف و introduction بسيط لاستخدامها، جميع المحتويات مأخوذة من الوثائق الرسمية، لمزيد من التفاصيل يمكنك زيارة cmd/go.
help
أول أمر يجب معرفته هو أمر help، من خلاله يمكنك قراءة كيفية استخدام الأوامر. هناك طريقتان للاستخدام، إذا كنت تريد الحصول على معلومات استخدام مختصرة، يمكنك إضافة علامة -h بعد الأمر المحدد، مثلاً
$ go env -h
usage: go env [-json] [-u] [-w] [var ...]
Run 'go help env' for details.سيعرض go باختصار طريقة استخدام هذا الأمر، كما أنه يلمح إلى أنه للحصول على معلومات أكثر تفصيلاً تحتاج إلى استخدام أمر help
$ go help env
usage: go env [-json] [-u] [-w] [var ...]
Env prints Go environment information.
By default env prints information as a shell script
(on Windows, a batch file). If one or more variable
names is given as arguments, env prints the value of
each named variable on its own line.
The -json flag prints the environment in JSON format
instead of as a shell script.
The -u flag requires one or more arguments and unsets
the default setting for the named environment variables,
if one has been set with 'go env -w'.
The -w flag requires one or more arguments of the
form NAME=VALUE and changes the default settings
of the named environment variables to the given values.
For more about environment variables, see 'go help environment'.استخدم أمر help بشكل جيد، من خلاله يمكنك الحصول على الكثير من المعلومات حول الأوامر.
doc
$ go doc -h
Usage of [go] doc:
go doc
go doc <pkg>
go doc <sym>[.<methodOrField>]
go doc [<pkg>.]<sym>[.<methodOrField>]
go doc [<pkg>.][<sym>.]<methodOrField>
go doc <pkg> <sym>[.<methodOrField>]
For more information run
go help doc
Flags:
-C dir
change to dir before running command
-all
show all documentation for package
-c symbol matching honors case (paths not affected)
-cmd
show symbols with package docs even if package is a command
-short
one-line representation for each symbol
-src
show source code for symbol
-u show unexported symbols as well as exportedأمر doc سيخرج تعليقات التوثيق للحزمة، الثابت، الدالة، النوع، المتغير، الطريقة وحتى حقول الهيكل المحددة. بدون أي معاملات، سيخرج تعليقات الحزمة الحالية
$ go docيمكنك أيضاً تحديد حزمة معينة للعرض، مثل عرض تعليقات توثيق حزمة runtime
$ go doc runtime
package runtime // import "runtime"
Package runtime contains operations that interact with Go's runtime system,
such as functions to control goroutines. It also includes the low-level type
information used by the reflect package; see reflect's documentation for the
programmable interface to the run-time type system.
......أو نوع معين
$ go doc unsafe.Pointer
package unsafe // import "unsafe"
type Pointer *ArbitraryType
Pointer represents a pointer to an arbitrary type. There are four special
operations available for type Pointer that are not available for other
types:
- A pointer value of any type can be converted to a Pointer.
- A Pointer can be converted to a pointer value of any type.
- A uintptr can be converted to a Pointer.
- A Pointer can be converted to a uintptr.
...أو دالة معينة
$ go doc runtime.GC
package runtime // import "runtime"
func GC()
GC runs a garbage collection and blocks the caller until the garbage
collection is complete. It may also block the entire program.له العلامات التالية شائعة الاستخدام
-u: عرض الأنواع الخاصة-all: عرض كل توثيق الحزمة المحددة-short: سطر واحد فقط من الوصف المختصر-src: إخراج الكود المصدري-cmd: للحزم التي تنتمي إلى أوامر go، إخراج توثيق الكود داخل الحزمة أيضاً.
مثل عرض متغير runtime.inf، هذا متغير غير مكشوف للخارج
$ go doc -u runtime.inf
package runtime // import "runtime"
var inf = float64frombits(0x7FF0000000000000)استخدام أمر doc بشكل جيد يمكن أن يساعدك في قراءة التوثيق بشكل أكثر راحة.
طريقة أخرى لقراءة توثيق الأوامر هي قراءة الكود المصدري، لأن توثيق بعض الأوامر لا يُكتب بالتفصيل، بل على العكس يكون هناك وصف أكثر تفصيلاً في الكود المصدري. بما أن هذه الأوامر كلها مكتوبة بـ go، فإن قراءتها تكون مريحة جداً. هذه الأوامر كلها موجودة في حزمة src/cmd، كل حزمة فرعية هي أمر منفصل، نقطة الدخول في ملف cmd/go/main.go
func init() {
base.Go.Commands = []*base.Command{
bug.CmdBug,
work.CmdBuild,
clean.CmdClean,
doc.CmdDoc,
envcmd.CmdEnv,
fix.CmdFix,
fmtcmd.CmdFmt,
generate.CmdGenerate,
modget.CmdGet,
work.CmdInstall,
list.CmdList,
modcmd.CmdMod,
workcmd.CmdWork,
run.CmdRun,
test.CmdTest,
tool.CmdTool,
version.CmdVersion,
vet.CmdVet,
help.HelpBuildConstraint,
help.HelpBuildmode,
help.HelpC,
help.HelpCache,
help.HelpEnvironment,
help.HelpFileType,
modload.HelpGoMod,
help.HelpGopath,
get.HelpGopathGet,
modfetch.HelpGoproxy,
help.HelpImportPath,
modload.HelpModules,
modget.HelpModuleGet,
modfetch.HelpModuleAuth,
help.HelpPackages,
modfetch.HelpPrivate,
test.HelpTestflag,
test.HelpTestfunc,
modget.HelpVCS,
}
}هنا ستجد جميع الأوامر الفرعية لـ go، ومعلومات توثيق المساعدة الخاصة بها.
bug
$ go help bug
usage: go bug
Bug opens the default browser and starts a new bug report.
The report includes useful system information.هذا الأمر ليس له أي معاملات أو علامات، سيفتح متصفحك الافتراضي ويزور واجهة issue في مستودع github.com/golang/go، لتسهيل الإبلاغ عن الأخطاء، ليس له أي استخدام آخر.
version
من خلال أمر version يمكنك عرض معلومات إصدار go الحالي.
$ go version -h
usage: go version [-m] [-v] [file ...]عند التنفيذ بدون أي معاملات، سيخرج إصدار لغة go الحالي
$ go version
go version go1.21.0 windows/amd64كما أنه يقبل مسار ملف كمعامل، سيخرج إصدار go المستخدم عند تجميع جميع الملفات الثنائية القابلة للتعرف في هذا المسار.
$ go version -v ./
buf.exe: go1.20.2
cobra-cli.exe: go1.21.0
dlv.exe: go1.20.2
goctl.exe: go1.20.2
goimports.exe: go1.20.2
golangci-lint.exe: go1.20.2
gopls.exe: go1.19.3
kratos.exe: go1.20.2
main.exe: go1.19.1
protoc-gen-go-grpc.exe: go1.20.2
protoc-gen-go-http.exe: go1.20.2
protoc-gen-go.exe: go1.20.2
protoc-gen-openapi.exe: go1.20.2
swag.exe: go1.21.0
wire.exe: go1.21.0حيث المعامل -v يحدد لأمر version محاولة إخراج إصدار go للملفات غير القابلة للتعرف، والمعامل -m يخرج معلومات الوحدة للملف الثنائي، وبعض معاملات التجميع، إليك مثال بسيط.
$ go version -v -m wire.exe
wire.exe: go1.21.0
path github.com/google/wire/cmd/wire
mod github.com/google/wire v0.5.0 h1:I7ELFeVBr3yfPIcc8+MWvrjk+3VjbcSzoXm3JVa+jD8=
dep github.com/google/subcommands v1.0.1 h1:/eqq+otEXm5vhfBrbREPCSVQbvofip6kIz+mX5TUH7k=
dep github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
dep golang.org/x/tools v0.0.0-20190422233926-fe54fb35175b h1:NVD8gBK33xpdqCaZVVtd6OFJp+3dxkXuz7+U7KaVN6s=
build -buildmode=exe
build -compiler=gc
build DefaultGODEBUG=panicnil=1
build CGO_ENABLED=1
build CGO_CFLAGS=
build CGO_CPPFLAGS=
build CGO_CXXFLAGS=
build CGO_LDFLAGS=
build GOARCH=amd64
build GOOS=windows
build GOAMD64=v1go نفسه هو ملف ثنائي، في الواقع بدون أي معاملات، go version يخرج إصدار لغة go للملف الثنائي نفسه، لأن جميع سلسلة أدوات cmd/go مُنفذة بلغة go نفسها.
env
من خلال أمر env يمكنك عرض معلومات جميع متغيرات بيئة go، تعديل هذه المتغيرات البيئية سيؤثر على سلوك سلسلة أدوات go.
$ go env -h
usage: go env [-json] [-u] [-w] [var ...]
Run 'go help env' for details.تنفيذ هذا الأمر بدون أي معاملات سيخرج قيم جميع متغيرات بيئة go
$ go env
set GO111MODULE=on
set GOARCH=amd64
...وضع اسم متغير بيئي معين كمعامل لإخراج قيمة هذا المتغير فقط
$ go env GO111MODULE
onإضافة -json يمكن إخراجها بصيغة json
$ go env -json
{
"AR": "ar",
"CC": "gcc",
......
}من خلال علامة -w، وبصيغة var=value كمعامل، سيتم تعديل قيمة متغير معين بشكل دائم
$ go env -w GO111MODULE=onاستخدام علامة -u يمكن إعادة متغير معين إلى قيمته الافتراضية
$ go env -u GO111MODULEتنفيذ go help environment يمكن عرض مقدمة لكل متغير بيئي
$ go help environment
The go command and the tools it invokes consult environment variables
for configuration. If an environment variable is unset or empty, the go
command uses a sensible default setting. To see the effective setting of
the variable <NAME>, run 'go env <NAME>'. To change the default setting,
run 'go env -w <NAME>=<VALUE>'. Defaults changed using 'go env -w'
are recorded in a Go environment configuration file stored in the
per-user configuration directory, as reported by os.UserConfigDir.
The location of the configuration file can be changed by setting
the environment variable GOENV, and 'go env GOENV' prints the
effective location, but 'go env -w' cannot change the default location.
See 'go help env' for details.
General-purpose environment variables:
GO111MODULE
Controls whether the go command runs in module-aware mode or GOPATH mode.
May be "off", "on", or "auto".
See https://golang.org/ref/mod#mod-commands.
GCCGO
The gccgo command to run for 'go build -compiler=gccgo'.
GOARCH
The architecture, or processor, for which to compile code.
Examples are amd64, 386, arm, ppc64.
GOBIN
The directory where 'go install' will install a command.
GOCACHE
The directory where the go command will store cached
information for reuse in future builds.
......فيما يلي مقدمة لبعض متغيرات البيئة شائعة الاستخدام
GOVERSION
قيمة هذا المتغير البيئي تعتمد على إصدار لغة go، ورقم الإصدار مأخوذ من ملف $GOROOT/VERSION، هذا الملف يسجل رقم إصدار go الحالي ووقت البناء.
$ cat $GOROOT/VERSION
go1.21.3
time 2023-10-09T17:04:35Zقيمة متغير runtime.Version هي نفسها قيمة GOVERSION، وهذا المتغير البيئي لا يمكن تعديله.
GOENV
في دليل $GOROOT يوجد ملف تكوين افتراضي اسمه go.env
$ cat $GOROOT/go.env
# This file contains the initial defaults for go command configuration.
# Values set by 'go env -w' and written to the user's go/env file override these.
# The environment overrides everything else.
# Use the Go module mirror and checksum database by default.
# See https://proxy.golang.org for details.
GOPROXY=https://proxy.golang.org,direct
GOSUMDB=sum.golang.org
# Automatically download newer toolchains as directed by go.mod files.
# See https://go.dev/doc/toolchain for details.
GOTOOLCHAIN=autoتنسيقه هو ببساطة صورة key=value، قيم المتغيرات البيئية المعدلة من خلال أمر go env -w key=value ستُكتب في ملف التكوين. لكن يمكن أيضاً عدم استخدام ملف التكوين الافتراضي، المتغير البيئي GOENV يمكن تحديد عنوان ملف تكوين env يدوياً، وقيمة المتغير البيئي GOENV يمكن فقط أن تُغطى بواسطة متغيرات البيئة لنظام التشغيل، ولا يمكن تعديلها بأمر go env -w.
GOHOSTARCH
يمثل بنية CPU للجهاز، للعرض فقط، قيمة هذا المتغير البيئي ليست مقروءة من ملف التكوين، ولا يمكن تعديلها.
GOHOSTOS
يمثل نظام التشغيل للجهاز، للعرض فقط، قيمة هذا المتغير البيئي ليست مقروءة من ملف التكوين، ولا يمكن تعديلها.
GOOS
عند التجميع، قيمة GOOS ستحدد نظام الهدف الذي سيُجمّع إليه الكود المصدري، القيمة الافتراضية هي GOHOSTOS، أي نظام التشغيل للجهاز، لديه الخيارات التالية
linuxdarwinwindowsnetbsdaixandroid
الأنظمة المدعومة فعلياً لا تقتصر على هذه، استخدم الأمر go tool dist list لعرض جميع القيم المدعومة
$ go tool dist list | awk -F '/' '{print $1}' | awk '!seen[$0]++'
aix
android
darwin
dragonfly
freebsd
illumos
ios
js
linux
netbsd
openbsd
plan9
solaris
wasip1
windowsGOARCH
عند التجميع، قيمة GOARCH ستحدد تعليمات بنية CPU المستخدمة عند التجميع، القيمة الافتراضية هي GOHOSTARCH، أي بنية CPU للجهاز، لديه الخيارات التالية
amd64386armppc64
البُنى المدعومة فعلياً أكثر من هذه، استخدم أمر go tool dist list لعرض جميع القيم المدعومة
$ go tool dist list | awk -F '/' '{print $2}' | awk '!seen[$0]++'
ppc64
386
amd64
arm
arm64
riscv64
wasm
loong64
mips
mips64
mips64le
mipsle
ppc64le
s390xيجب الانتباه إلى أن GOOS و GOARCH لا يمكن دمجهما بشكل عشوائي، بعض أنظمة التشغيل تدعم فقط بنى CPU معينة.
GOROOT
GOROOT يمثل الدليل الجذر لموقع تثبيت لغة go، قيمة GOROOT لا يمكن تعديلها مباشرة، ويمكن فقط أن تُغطى بواسطة متغيرات بيئة نظام التشغيل.
$ ls $GOROOT -1
api
bin
codereview.cfg
CONTRIBUTING.md
doc
go.env
lib
LICENSE
misc
PATENTS
pkg
README.md
SECURITY.md
src
test
VERSIONفي الدليل الجذر توجد المجلدات أو الملفات المهمة التالية
lib، يخزن بعض التبعيات، حالياً مكتبة واحدة فقط تحتوي على معلومات المنطقة الزمنية لجميع دول العالم، موجودة في$GOROOT/lib/time، الملف الثنائي المُجمّع لن يحتوي على هذه المعلومات الزمنية.pkg، يخزن بعض مكتبات الأدوات والملفات الرأسية، مثل أمرgo toolسيبحث عن الملفات الثنائية لسلسلة أدوات go في دليل$GOROOT/pkg/toolbin، يخزن الملفات الثنائية، افتراضياً يوجد فقطgoوgofmtكملفات قابلة للتنفيذ، يجب إضافة$GOROOT/binإلى متغيرات النظام، وإلا لن تتمكن من استخدام أوامر go.src، يخزن الكود المصدري لـ goVERSION، هذا الملف يخزن معلومات إصدار لغة gogo.env، هذا الملف هو ملف تكوينenvالافتراضي
GOPATH
القيمة الافتراضية لـ GOPATH هي $HOME/go، قيمة هذا المتغير البيئي تحدد أين البحث عن الملفات المستوردة عند تحليل جمل import. في الأيام الأولى قبل وجود gomod، كان GOPATH مخصصاً لتخزين المكتبات الخارجية المختلفة، وهيكله كالتالي
GOPATH=/home/user/go
/home/user/go/
src/
foo/
bar/ (go code in package bar)
x.go
quux/ (go code in package main)
y.go
bin/
quux (installed command)
pkg/
linux_amd64/
foo/
bar.a (installed package object)بعد ظهور gomod، أصبح GOPATH مجرد مكان لتخزين التبعيات التي ينزلها go get، والملفات الثنائية التي ينزلها ويُجمّعها go install. يجب الانتباه إلى أن موقع GOPATH لا يمكن أن يكون نفس GOROOT، وإلا لن يكون له أي تأثير.
$ go env GOBIN
warning: GOPATH set to GOROOT (/home/user/go) has no effectحتى وقت كتابة هذا المقال، وصل إصدار لغة go إلى go1.21.3، وباستثناء المشاريع القديمة جداً، لا أحد يستخدم gopath لإدارة التبعيات بعد.
GOBIN
GOBIN يُستخدم لتخزين الملفات الثنائية القابلة للتنفيذ الخارجية التي ينزلها ويُجمّعها go install، قيمته الافتراضية هي $GOPATH/bin. مثل $GOROOT/bin، يجب إضافة هذا الدليل إلى متغيرات بيئة نظام التشغيل، وإلا لن تتمكن من استخدام الملفات الثنائية في دليل GOBIN.
GOMODCACHE
GOMODCACHE يمثل موقع تخزين التبعيات التي ينزلها go get، قيمته الافتراضية هي $GOPATH/pkg/mod. هيكل تخزينه كالتالي
$GOMODCACHE/domain/username/project@verionفي نفس مستوى الدليل سيكون هناك مجلد اسمه sumdb، لتخزين المعلومات المتعلقة بقاعدة بيانات المجموع الاختباري للتبعيات.
GOCACHE
يخزن معلومات الذاكرة المؤقتة للتجميع، قيمته الافتراضية هي $HOME/.cache/go-build، سيُنشأ ملف README في هذا الدليل.
$ cat $(go env GOCACHE)/README
This directory holds cached build artifacts from the Go build system.
Run "go clean -cache" if the directory is getting too large.
Run "go clean -fuzzcache" to delete the fuzz cache.
See golang.org to learn more about Go.كل build تُنتج العديد من الملفات، سيقوم go بتخزين هذه الملفات مؤقتاً لإعادة استخدامها في التجميع التالي.
GOTEMPDIR
للملفات المؤقتة المنتجة أثناء التجميع، مثل الملف الثنائي المؤقت الذي سيشغله go run. قيمته الافتراضية هي الدليل المؤقت المحدد بواسطة نظام التشغيل، على mac أو linux يكون /tmp، وعلى windows يكون %TEMP%، ويمكن أيضاً تعديله إلى موقع يحدده المستخدم.
GO111MODULE
هذا المتغير البيئي يشير إلى الطريقة المستخدمة لإدارة تبعيات مشروع go، لديه ثلاث قيم متاحة
off، إيقاف gomod، استخدام gopath، وتجاهل جميع ملفاتgo.modon، استخدام gomod، عدم استخدام gopath (الافتراضي).auto، الاستشعار التلقائي، إذا كان ملف المشروع يحتوي علىgo.modسيستخدم gomod للإدارة
TIP
لماذا يُسمى GO111MODULE وليس GOMODULE مباشرة، لأن gomod طُرح لأول مرة في إصدار go1.11.
GOPROXY
وكيل وحدة go، القيمة الافتراضية هي https://proxy.golang.org,direct، عناوين URL مفصولة بفواصل، direct تعني استخدام VCS مباشرة وتخطي وكيل الوحدة، سيتم تنفيذ الأخيرة فقط عندما يتعذر الوصول إلى الأولى، وهناك خيار متاح وهو off، يعني حظر تنزيل أي وحدة. بالإضافة إلى ذلك، يمكن أن يكون GOPROXY عنوان ملف، مثل
GOPROXY=file://$(go env GOMODCACHE)/cache/downloadمن خلال go get -x يمكنك عرض الأوامر المنفذة أثناء عملية تنزيل التبعيات، لمعرفة ما إذا كان قد مر بالوكيل.
$ go get -x github.com/spf13/cast
# get https://goproxy.cn/github.com/@v/list
# get https://goproxy.cn/github.com/spf13/cast/@v/list
# get https://goproxy.cn/github.com/spf13/@v/list
# get https://goproxy.cn/github.com/spf13/@v/list: 404 Not Found (0.118s)
# get https://goproxy.cn/github.com/@v/list: 404 Not Found (0.197s)
# get https://goproxy.cn/github.com/spf13/cast/@v/list: 200 OK (0.257s)
# get https://goproxy.cn/github.com/spf13/cast/@v/v1.5.1.info
# get https://goproxy.cn/github.com/spf13/cast/@v/v1.5.1.info: 200 OK (0.013s)
# get https://goproxy.cn/github.com/spf13/cast/@v/v1.5.1.mod
# get https://goproxy.cn/github.com/spf13/cast/@v/v1.5.1.mod: 200 OK (0.015s)
# get https://goproxy.cn/sumdb/sum.golang.org/supported
# get https://goproxy.cn/sumdb/sum.golang.org/supported: 200 OK (0.064s)
# get https://goproxy.cn/sumdb/sum.golang.org/lookup/github.com/spf13/cast@v1.5.1
# get https://goproxy.cn/sumdb/sum.golang.org/lookup/github.com/spf13/cast@v1.5.1: 200 OK (0.014s)
# get https://goproxy.cn/sumdb/sum.golang.org/tile/8/0/x079/736
# get https://goproxy.cn/sumdb/sum.golang.org/tile/8/0/x079/736: 200 OK (0.016s)
# get https://goproxy.cn/sumdb/sum.golang.org/tile/8/0/x068/334
# get https://goproxy.cn/sumdb/sum.golang.org/tile/8/1/266
# get https://goproxy.cn/sumdb/sum.golang.org/tile/8/0/x068/334: 200 OK (0.023s)
# get https://goproxy.cn/sumdb/sum.golang.org/tile/8/1/266: 200 OK (0.028s)
go: downloading github.com/spf13/cast v1.5.1
# get https://goproxy.cn/github.com/spf13/cast/@v/v1.5.1.zip
# get https://goproxy.cn/github.com/spf13/cast/@v/v1.5.1.zip: 200 OK (0.024s)
go: added github.com/spf13/cast v1.5.1استخدام وكيل الوحدة يمكن أن يحسن بفعالية سرعة تنزيل الوحدات، للمستخدمين في الصين لا يمكن الوصول إلى الوكيل الرسمي الافتراضي بدون وكيل، حالياً وكلاء الوحدات الخارجيين الموثوقين المتاحين كالتالي
https://proxy.golang.com.cn، مفتوح المصدر ويوفر نسخة المؤسساتhttps://goproxy.cn، توفره Qiniu Cloud ومفتوح المصدر
بالطبع هناك أيضاً حلول مفتوحة المصدر لبناء وكيل وحدات ذاتي: goproxy
GOSUMDB
GOSUMDB يُستخدم لتعيين عنوان قاعدة بيانات فحص المجموع الاختباري للمكتبات التابعة، الافتراضي هو sum.golang.org، عند تعيينك لوكيل، سيصل go إلى قاعدة بيانات الفحص من خلال الوكيل.
GOPRIVATE
المتغير البيئي GOPRIVATE يُستخدم لتعيين المكتبات الخاصة، المكتبات المتطابقة لن تُفحص من خلال sumdb، ولن تمر بالوكيل، بل ستُنزل التبعيات مباشرة من خلال VCS. يدعم هذا الإعداد أحرف البدل، مفصولة بفواصل، كما يلي، جميع التبعيات التي تنتهي بـ corp.example.com واسمها github.com/gohper/myproject لن تمر بالوكيل و sumdb.
GOPRIVATE=*.corp.example.com,github.com/gohper/myprojectيمكن أيضاً تعيين مستخدم أو منظمة معينة مباشرة
GOPRIVATE=github.com/gopher,github.com/myorganizationGONOPROXY
يشير إلى التبعيات التي لا تحتاج للمرور بالوكيل، القواعد نفسها GOPRIVATE، وستغطي GOPRIVATE.
GONOSUMDB
يشير إلى التبعيات التي لا تحتاج للمرور بقاعدة بيانات الفحص، القواعد نفسها GOPRIVATE، وستغطي GOPRIVATE.
GOINSECURE
يشير إلى التبعيات التي تُنزل مباشرة باستخدام VCS، القواعد نفسها GOPRIVATE، وستُغطى بواسطة GONOPROXY و GONOSUMDB.
GOVCS
تعيين نظام التحكم في الإصدار لإدارة الوحدات، الافتراضي public:git|hg,private:all. يمكن أيضاً تحديد VCS لنطاقات معينة، مثلاً
GOVCS=github.com:git,evil.com:off,*:git|hgفي القيود أعلاه، github يمكنه استخدام git فقط، evil.com غير مسموح له، استخدام | يمكن أن يمثل عدة VCS. إذا لم تضع أي قيود، يمكن الإعداد كالتالي
GOVCS=*:allإذا لم يُسمح بأي VCS، يمكن الإعداد كالتالي
GOVCS=*:offGOWORK
تعيين ما إذا كان سيتم تفعيل مساحة العمل، الافتراضي فارغ أي مفعّل، إذا عُيّن إلى off فلن يُفعّل، وسيتم تجاهل جميع ملفات go.work.
GOTOOLDIR
تعيين موقع سلسلة أدوات go المستخدمة، الافتراضي هو $GOROOT/pkg/tool، سلسلة الأدوات الافتراضية مخزنة أيضاً في هذا الموقع.
GODEBUG
تعيين خيارات التصحيح، على شكل أزواج مفتاح-قيمة للتحكم في بعض سلوكيات تنفيذ برنامج go، مثلاً
GODEBUG=http2client=0,http2server=0هذه الإعدادات لتسهيل الرجوع إلى السلوك القديم عند حدوث تغييرات غير متوافقة أثناء عملية تحديث الإصدار، مثلاً في 1.21 لم يعد مسموحاً بـ panic(nil)، لهذا سجّل go الرسمي خصيصاً GODEBUG History، انتقل إلى GODEBUG لمعرفة المزيد من التفاصيل.
CGO_ENABLED
يشير إلى ما إذا كان سيتم تفعيل cgo، الافتراضي 1، أي مفعّل، تعيينه إلى 0 يلغيه.
هذه المتغيرات البيئية كلها شائعة الاستخدام، أما对于那些不那么常用的 لا يوجد مقدمة كثيرة، مثل CGO، WASM وما شابه، إذا كنت مهتماً يمكنك التعرف عليها بنفسك.
build
go يدعم نوعين من المجمعات، gccgo و gc. gcc هو مجمع C/C++ عريق، يدعم لغات متعددة بما فيها go، أما gc الثاني فلا يشير إلى جمع المهملات، بل يشير إلى go compiler، في go1.5 أكملت go الاعتماد الذاتي، gc هو مجمع مكتوب بالكامل بلغة go، الكود المصدري له موجود في حزمة cmd/compile، وبما أنه مُنفذ بالكامل بلغة go، فمن السهل جداً فهم وتعلم آلياته الداخلية. بشكل افتراضي، يستخدم المجمع gc للتجميع. وبالمناسبة، مصحح أخطاء go أيضاً نوعان، gdb و dlv، الأول هو مصحح C/C++ عريق، يدعم لغات متعددة بما فيها go، والثاني هو مصحح أخطاء مكتوب بلغة go، دعمه للغة go أكثر ودية، وهو أيضاً مفتوح المصدر، يُنصح باستخدام الأخير.
وظيفة أمر build هي تجميع ملفات go المصدرية إلى ملفات ثنائية قابلة للتنفيذ، ستختبر تجربة تجميع سريعة جداً، وهذه أيضاً إحدى خصائص لغة go.
$ go build -h
usage: go build [-o output] [build flags] [packages]
Run 'go help build' for details.يقبل ثلاثة معاملات، واحد هو مسار إخراج الملف المشار إليه بعلامة -o، وواحد هو علامات البناء build flags لتعريف سلوك التجميع، والأخير هو الحزمة المراد تجميعها، يجب أن يكون هذا المعامل في النهاية. إليك مثال بسيط، بدون استخدام علامات البناء.
# Windows
$ go build -o .\bin\golearn.exe golearn
# macOS / Linux
$ go build -o ./bin/golearn golearn./bin/golearn.exe يمثل مسار الإخراج، golearn يمثل الوحدة المراد تجميعها، ويمكن أن يكون أيضاً ملف مدخل، أو مجلد. مثل المثال البسيط التالي الذي يأخذ ملف main.go كملف مدخل للتجول.
# Windows
$ go build -o .\bin\golearn.exe main.go
# macOS / Linux
$ go build -o ./bin/golearn main.goعند التجميع سيتم تجاهل جميع الملفات التي تنتهي بـ _test.go، لأن هذه الملفات حسب الاصطلاح هي ملفات اختبار.
بالإضافة إلى ذلك، يدعم أمر build عدداً كبيراً من علامات البناء للتحكم في بعض السلوكيات أثناء التجميع.
-x: إخراج التعليمات التفصيلية أثناء عملية التجميع-n: مشابه لـ-x، لكن الفرق أنه فقط يخرج هذه التعليمات، لكن لا ينفذها فعلياً.-v: إخراج الحزم المُجمّعة-p: عدد التزامن أثناء عملية التجميع-a: فرض إعادة البناء، حتى لو كان أحدث إصدار.-compiler: تحديد المجمع المستخدم،gccgoأوgc، الأخير هو مجمع مكتوب بـ go.-race: تفعيل اكتشاف التسابق-msan: تفعيل تحليل الذاكرة-asan: تفعيل تحليل العناوين-cover: تفعيل اكتشاف تغطية الكود-buildmode: تحديد وضع التجميع، الخيارات المتاحة هيarchive،c-archive،c-shared،default،shared،exe،pie،plugin.-pgo، تحديد ملف pgo-trimpath: إزالة بادئة مسار الملف المصدر، مثل المسار النسبي/var/lib/go/src/main.go، بعد الإزالة سيكون اسم الملف الذي يمكن الحصول عليه من خلالruntimeأثناء التشغيل هو فقط المسار النسبي بالنسبة لمسار الوحدة/main.go، بعد تفعيل هذا، سيزداد وقت التجميع بشكل ملحوظ، حوالي 20-40%، حسب عدد الملفات.-toolexec، بعض أوامر go المنفذة قبل التجميع، التنسيق هو-toolexec 'cmd args'.-gcflags: تحديد بعض علامات gc للمجمع-gccgoflags: تحديد بعض علامات gccgo للمجمع-ldflags: تحديد بعض علامات أداة link
للحصول على بعض المعاملات المارة مثل ldflags، يمكنك تمرير "-help" للحصول على قيمه المحتملة، مثل
$ go build -ldflags -help
usage: link [options] main.o
-B note
add an ELF NT_GNU_BUILD_ID note when using ELF
-E entry
set entry symbol name
......هذه هي الأكثر استخداماً، أما غيرها غير شائعة الاستخدام فيمكنك التعرف عليها بنفسك.
gcflags
من خلال gcflags يمكنك تمرير بعض المعاملات للمجمع gc للتحكم في سلوكيات محددة، تنسيق استخدامه هو -gcflags="pattern=args list"، args list هي قائمة المعاملات، pattern هو نطاق التأثير، له القيم المتاحة التالية
main، مسار الحزمة العليا حيث يوجد ملف المدخلall، الوحدة الحالية وجميع تبعيات الوضع الحاليstd، المكتبة القياسيةcmd، يؤثر على جميع الملفات المصدرية في حزمةcmd- أحرف البدل، مثل
.،./...،cmd/....
قواعد pattern هذه تنطبق على جميع العلامات التي تدعم هذا التنسيق، مثل ldflags. من خلال الأمر التالي لعرض قيم معاملاته المتاحة
$ go build -gcflags -help
用法:compile [选项] file.go...
-% 调试非静态初始化器
-+ 编译运行时
-B 禁用边界检查
-C 禁用错误消息中的列号打印
-D path
设置本地导入的相对路径
-E 调试符号导出
-I directory
添加目录到导入搜索路径
-K 调试缺失的行号
-L 对于受 //line 指令影响的错误位置,同时显示实际源文件名
-N 禁用优化
-S 打印汇编列表
-V 打印版本并退出
-W 类型检查后调试解析树
......فيما يلي مقدمة لبعض المعاملات شائعة الاستخدام
-S: إخراج صورة التجميع للكود-N: إيقاف تحسينات التجميع-m: إخراج قرارات التحسين-l: إيقاف الدمج التلقائي للدوال-c: عدد التزامن في التجميع-dwarf: توليد علامات DWARF
مثلاً إذا كنت تريد عرض صورة التجميع للكود، يمكنك استخدام المعامل -S، ويجب أيضاً إيقاف التحسين والدمج التلقائي، حتى تتم استعادة شكله الأصلي، كالتالي
$ go build -trimpath -gcflags="-N -l -S" main.go
main.main STEXT size=171 args=0x0 locals=0x58 funcid=0x0 align=0x0
0x0000 00000 (./main.go:9) TEXT main.main(SB), ABIInternal, $88-0
0x0000 00000 (./main.go:9) CMPQ SP, 16(R14)
0x0004 00004 (./main.go:9) PCDATA $0, $-2
0x0004 00004 (./main.go:9) JLS 161
0x000a 00010 (./main.go:9) PCDATA $0, $-1
0x000a 00010 (./main.go:9) PUSHQ BP
0x000b 00011 (./main.go:9) MOVQ SP, BP
0x000e 00014 (./main.go:9) SUBQ $80, SP
0x0012 00018 (./main.go:9) FUNCDATA $0, gclocals·J5F+7Qw7O7ve2QcWC7DpeQ==(SB)
0x0012 00018 (./main.go:9) FUNCDATA $1, gclocals·bDfKCdmtOiGIuJz/x+yQyQ==(SB)
0x0012 00018 (./main.go:9) FUNCDATA $2, main.main.stkobj(SB)
0x0012 00018 (./main.go:10) MOVUPS X15, main..autotmp_0+40(SP)
0x0018 00024 (./main.go:10) LEAQ main..autotmp_0+40(SP), CX
0x001d 00029 (./main.go:10) MOVQ CX, main..autotmp_2+32(SP)ldflags
من خلال ldflags يمكنك تمرير بعض المعاملات للرابط للتحكم في سلوكيات محددة، من خلال الأمر التالي لعرض جميع القيم المتاحة لـ ldflags، تقريباً عشرين أو ثلاثين.
$ go build -ldflags -help
usage: link [options] main.o
-B note
add an ELF NT_GNU_BUILD_ID note when using ELF
-E entry
set entry symbol name
-H type
set header type
-I linker
use linker as ELF dynamic linker
-L directory
add specified directory to library path
-R quantum
set address rounding quantum (default -1)
-T int
set the start address of text symbols (default -1)
-V print version and exit
-X definition
add string value definition of the form importpath.name=value
-a no-op (deprecated)
.....المعامل -X في ldflags هو وظيفة عملية جداً، يمكنه تعريف قيم متغيرات السلسلة في حزمة محددة أثناء الربط. من خلال هذه الوظيفة، يمكننا بسهولة حقن بعض المعلومات الوصفية أثناء التجميع. وبما أنه مجرد متغير، فمن السهل أيضاً الحصول عليه أثناء التشغيل، إليك مثال بسيط.
package main
import "fmt"
var (
Version string
)
func main() {
fmt.Println(Version)
}تنفيذ الأمر
go build -ldflags "-X main.Version=$(git describe --always)" main.goبعد التشغيل سيتم إخراج المجموع الاختباري sha1 لـ git commit.
5e3fd7aهناك أيضاً بعض المعاملات العملية الأخرى مثل
-w: عدم توليد DWARF، هذه معلومات لتسهيل تصحيح الكود المصدري.-s: تعطيل جدول الرموز
هذان يستخدمان معاً عادةً، يمكن تقليل حجم الملف الثنائي المُجمّع بشكل ملحوظ، حوالي 40%-50%، والعيب واضح أيضاً، لا يمكن التصحيح، إليك مثال.
$ go build -ldflags="-w -s" main.goالتجميع المتقاطع
تجميع لغة go له خاصيتان رئيسيتان، الأولى هي السرعة، والخاصية الكبيرة الأخرى هي التجميع المتقاطع، التجميع المتقاطع يعني القدرة على التجميع محلياً إلى كود هدف لأنظمة أخرى، مثلاً على windows التجميع إلى ملفات ثنائية لـ linux أو darwin، والعكس صحيح. التجميع المتقاطع يدعم العديد من اللغات، هذا ليس شيئاً نادراً، لكن التجميع المتقاطع في go بسيط جداً، يحتاج فقط الخطوات التالية
- تعيين متغير البيئة GOOS، اختيار نظام التشغيل الهدف
- تعيين متغير البيئة GOARCH، اختيار بنية CPU الهدف
- استخدام
go buildللتجميع كالمعتاد
العملية برمتها قصيرة جداً، لا تحتاج استخدام أدوات أو إعدادات إضافية، والسرعة سريعة كالمعتاد. كالتالي
build_linux:
SET CGO_ENABLED=0
SET GOOS="linux"
SET GOARCH="amd64"
go build -o golearn main.go
build_mac:
SET CGO_ENABLED=0
SET GOOS="darwin"
SET GOARCH="amd64"
go build -o golearn main.go
build_win:
SET CGO_ENABLED=0
SET GOOS="win"
SET GOARCH="amd64"
go build -o golearn.exe main.go
.PHONY: build_linux \
build_mac \
build_winالخطوة الأولى SET CGO_ENABLED=0 تعطل cgo، بمجرد استخدام cgo في كودك، لن تتمكن من استخدام التجميع المتقاطع بشكل طبيعي. الخطوة الثانية SET GOOS تعيين النظام الهدف، الخيارات المتاحة هي linux، darwin، windows، netbsd. الخطوة الثالثة تعيين بنية CPU، SET GOARCH، الخيارات المتاحة هي amd64، 386، arm، ppc64. الخطوة الأخيرة هي التجميع كالمعتاد.
التحكم في التجميع
أمر build يمكنه التحكم في تأثير التجميع من خلال tags، وهو موجود في الكود المصدري على شكل توجيه، انظر المثال، ملف product.go
// +build product
package main
import "fmt"
func main() {
fmt.Println("product")
}ملف debug.go
// +build debug
package main
import "fmt"
func main() {
fmt.Println("debug")
}كلاهما لديه توجيه // +build، يشير إلى الحالات التي سيُجمّع فيها. تنسيقه الأساسي هو
// +build tag1 tag2
package pkg_nameهناك عدة قواعد يجب اتباعها
- يجب أن يكون هناك مسافة بين
//و+build - يجب أن يكون أعلى إعلان الحزمة
- يجب أن يُفصل عن إعلان الحزمة بسطر فارغ
بالإضافة إلى ذلك، يمكن تحقيق التحكم المنطقي من خلال تباعد بسيط، المسافة تعني OR، الفاصلة تعني AND، ! تعني NOT. مثل المثال التالي
// +build windows linux
package pkg_nameيعني أنه في نظام windows أو linux سيُجمّع الملف الحالي.
// +build windows,amd64,!cgo linux,i386,cgo
package pkg_nameهذا المثال يعني أنه في نظام windows بنية amd64 وبدون تفعيل cgo أو نظام linux بنية i386 وتفعيل cgo سيُجمّع. إذا كنت تريد ببساطة عدم مشاركة ملف معين في التجميع، يمكنك استخدام ignore.
// +build ignore
package pkg_nameيمكن أيضاً وجود عدة أسطر من التوجيهات
// +build windows
// +build amd64
package pkg_nameالتوجيهات متعددة الأسطر تُعامل بطريقة AND. بالنسبة لعلامات المنصة والبنية هذه، سيتم تمريرها تلقائياً من go أثناء التجميع، يمكننا أيضاً تمرير علامات مخصصة، لنأخذ الملفين السابقين كمثال
$ go build -tags="debug" . && ./golearn.exe
debug
$ go build -tags="product" . && ./golearn.exe
productيمكنك أن ترى أن الإخراج مختلف عند تمرير علامات مختلفة، وبذلك يكون الهدف من التحكم في التجميع قد تحقق.
run
أمر run وأمر build كلاهما سيُجمّع الكود المصدري، الفرق هو أن أمر run سيشغله مباشرة بعد اكتمال التجميع. أمر run لتسريع سرعة التجميع، لا يُنشئ معلومات التصحيح أثناء عملية التجميع، لذلك لا يدعم التصحيح، ويُنشئ فقط ملفاً ثنائياً مؤقتاً، يُخزن عادةً في دليل GOTMEPDIR، مثل /temp/go-build2822241271/b001/exe/main.exe.
$ go run -h
usage: go run [build flags] [-exec xprog] package [arguments...]
Run 'go help run' for details.يدعم أيضاً علامات البناء لأمر build، ويوفر معاملاً -exec لتحديد البرنامج الذي سيشغل الملف الثنائي، [arguments...] يشير إلى معاملات تشغيل البرنامج. إليك مثال
package main
import (
"fmt"
"os"
)
var (
Version string
)
func main() {
fmt.Println(Version)
fmt.Println(os.Args[1:])
}استخدام go run للتشغيل
$ go run -ldflags="-X main.Version=$(git describe --always)" main.go hello
5e3fd7a
[hello]بشكل عام استخدامه مشابه جداً لـ go build، لذلك لن نقدم الكثير من التفاصيل.
tool
أمر tool نفسه ليس له أي وظيفة، وظيفته هي استدعاء الأدوات في دليل cmd/ مباشرةً، مثل cmd/compile هو المجمع المدمج. من خلال go tool يمكن استدعاء هذه الأدوات مباشرةً، دون الحاجة لتنفيذ الملفات الثنائية لهذه الأدوات يدوياً.
$ go tool -h
usage: go tool [-n] command [args...]استخدام المعامل -n لطباعة جميع معاملات الأوامر المدعومة
$ go tool -n
addr2line
asm
buildid
cgo
compile
covdata
cover
doc
fix
link
nm
objdump
pack
pprof
test2json
trace
vetهذه الأدوات مخزنة في دليل GOROOT/pkg/tool، ومُجمّعة حسب نظام التشغيل وبنية CPU، كالتالي.
$ ls $GOROOT/pkg/tool/windows_amd64/ -1
addr2line.exe*
asm.exe*
buildid.exe*
cgo.exe*
compile.exe*
covdata.exe*
cover.exe*
doc.exe*
fix.exe*
link.exe*
nm.exe*
objdump.exe*
pack.exe*
pprof.exe*
test2json.exe*
trace.exe*
vet.exe*استخدام go doc cmd/command لعرض استخدام كل أمر، مثل
$ go doc cmd/compile
Usage:
go tool compile [flags] file...
The specified files must be Go source files and all part of the same package.
The same compiler is used for all target operating systems and architectures.
The GOOS and GOARCH environment variables set the desired target.
Flags:
-D path
Set relative path for local imports.
-I dir1 -I dir2
Search for imported packages in dir1, dir2, etc,
after consulting $GOROOT/pkg/$GOOS_$GOARCH.
-L
Show complete file path in error messages.
...العلامات التي يدعمها cmd/compile هي نفسها العلامات التي يدعمها gcflags المذكور سابقاً. الفرق بين go tool compile و go build هو أن الأول مسؤول فقط عن التجميع، ويمكنه فقط أخذ الملفات كمعاملات، بينما الثاني يمكنه أخذ المجلدات، الحزم، الملفات كمعاملات، ولا يقوم فقط بتجميع الكود المصدري، بل مسؤول أيضاً عن ربط الملفات، مسح الملفات غير المفيدة وغيرها، الأول جزء من الأخير. يمكننا طباعة الأوامر المنفذة أثناء عملية build
$ go build -n main.go
#
# internal/goarch
#
mkdir -p $WORK\b004\
cat >$WORK\b004\importcfg << 'EOF' # internal
# import config
EOF
"/golang/pkg/tool/windows_amd64/compile.exe" -o "$WORK/b004/_pkg_.a" -trimpath "$WORK/b004=>" -p internal/goarch -std -+ -complete -buildid 3gunEkUExGdhOPa2rFsh/3gunEkUExGdhOPa2rFsh -goversion go1.21.0 -c=4 -nolocalimports -importcfg "$WORK/b004/importcfg" -pack "/golang/src/internal/goarch/goarch.go" "/golang/src/internal/goarch/goarch_amd64.go" "/golang/src/internal/goarch/zgoarch_amd64.go"
"/golang/pkg/tool/windows_amd64/buildid.exe" -w "$WORK/b004/_pkg_.a" # internal
...في العملية يمكنك رؤية هذا الجزء /golang/pkg/tool/windows_amd64/compile.exe، وهو استدعاء المجمع. بالإضافة إلى compile، هناك العديد من الأدوات الأخرى التي يمكن استدعاؤها، والعديد من أوامر go في الواقع هي أسماء مستعارة لها.
clean
أمر clean يُستخدم لمسح الملفات الكائنة المنتجة أثناء عملية التجميع
$ go clean -h
usage: go clean [clean flags] [build flags] [packages]
Run 'go help clean' for details.يدعم العلامات التالية
-i: مسح الملفات الأرشيفية أو الملفات الثنائية المقابلة-n: طباعة الأوامر التي سيتم تنفيذها أثناء عملية المسح لكن بدون تنفيذها فعلياً-x: طباعة الأوامر التي سيتم تنفيذها أثناء عملية المسح وتنفيذها-r: المسح بشكل متكرر من خلالimport path-cache، مسح جميع الذاكرات المؤقتة الناتجة عنgo build-testcache: مسح جميع ذاكرات الاختبار المؤقتة الناتجة-modcache: مسح جميع ذاكرات الوحدات المنزلة-fuzzcache: مسح الذاكرات المؤقتة الناتجة عنfuzz test.
عند استخدام go tool compile، يتم استدعاء أمر المجمع مباشرةً، على عكس go build الذي يقوم بالكثير من المعالجات اللاحقة، لذلك ستُنتج ملفات كائنة. مثل تنفيذ الأمر التالي
go tool compile -N -S -l main.goسيُنتج ملفاً اسمه main.o، استخدم أمر go clean لمسحه. أو استخدام المعامل -n لطباعة الأوامر التي سيتم تنفيذها.
$ go clean -n
rm -f golearn golearn.exe golearn golearn.exe golearn.test golearn.test.exe golearn.test golearn.test.exe api api.exe main main.exeمسح ذاكرة التجميع المؤقتة، سيحذف الذاكرة المؤقتة للتجول المنتجة في دليل GOCACHE
$ go clean -cache -n
rm -r /cache/00 /cache/01 /cache/02مسح الذاكرة المؤقتة لـ fuzz test، هذه الذواكر مخزنة افتراضياً في دليل GOCACHE/fuzz/
$ go clean -fuzzcache -n
rm -rf /cache/fuzzfix
لغة go حتى وقت كتابة هذا المقال لها عشر سنوات، خلال عملية التحديث والتعديل المستمرة للغة، من المحتم ظهور بعض عدم التوافق بسبب تغييرات API، أمر fix وُجد لهذا الغرض، سيكتشف APIs القديمة في الملفات المصدرية ويستبدلها بـ APIs الجديدة.
$ go fix -h
usage: go fix [-fix list] [packages]
Run 'go help fix' for details.يدعم المجلدات، أسماء الملفات، الدلائل كمعاملات، يقبل علامة -fix لتمرير معاملات للإشارة إلى نوع التعديل، يمكن من خلال أمر got tool fix -help عرض القيم المتاحة
$ go tool fix -help
usage: go tool fix [-diff] [-r fixname,...] [-force fixname,...] [path ...]
-diff
display diffs instead of rewriting files
-force string
force these fixes to run even if the code looks updated
-go string
go language version for files
-r string
restrict the rewrites to this comma-separated list
Available rewrites are:
buildtag
Remove +build comments from modules using Go 1.18 or later
cftype
Fixes initializers and casts of C.*Ref and JNI types
context
Change imports of golang.org/x/net/context to context
egl
Fixes initializers of EGLDisplay
eglconf
Fixes initializers of EGLConfig
gotypes
Change imports of golang.org/x/tools/go/{exact,types} to go/{constant,types}
jni
Fixes initializers of JNI's jobject and subtypes
netipv6zone
Adapt element key to IPAddr, UDPAddr or TCPAddr composite literals.
https://codereview.appspot.com/6849045/
printerconfig
Add element keys to Config composite literals.إليك مثالاً، الكود المصدري يستخدم حزمة golang.org/x/net/context
package main
import (
"fmt"
"golang.org/x/net/context"
)
func main() {
background := context.Background()
fmt.Println(background.Err())
}استخدام go fix للتصحيح، واستبدالها بحزمة context في المكتبة القياسية، يمكننا استخدام الأمر التالي للقيام بالاستبدال
$ go fix -fix context main.goيمكن أيضاً عدم الاستبدال، ومشاهدة التغييرات قبل وبعد الملف.
$ go tool fix -r context -diff main.go
main.go: fixed context
diff main.go fixed/main.go
--- main.go
+++ fixed/main.go
@@ -1,8 +1,8 @@
package main
import (
+ "context"
"fmt"
- "golang.org/x/net/context"
)
func main() {لغة go وُجدت لأكثر من عشر سنوات ولديها فقط تسعة معاملات استبدال متاحة، مما يدل على أن التوافق محفوظ بشكل جيد.
fmt
أمر fmt هو أداة التنسيق المدمجة في لغة go، تُستخدم لتنسيق ملفات go المصدرية.
$ go fmt -h
usage: go fmt [-n] [-x] [packages]
Run 'go help fmt' for details.من خلال أمر go doc gofmt لعرض توثيقه التفصيلي
$ go doc cmd/gofmt
Gofmt formats Go programs. It uses tabs for indentation and blanks for
alignment. Alignment assumes that an editor is using a fixed-width font.
Usage:
gofmt [flags] [path ...]
The flags are:
-d
Do not print reformatted sources to standard output.
If a file's formatting is different than gofmt's, print diffs
to standard output.
-e
Print all (including spurious) errors.
-l
Do not print reformatted sources to standard output.
If a file's formatting is different from gofmt's, print its name
to standard output.
-r rule
Apply the rewrite rule to the source before reformatting.
-s
Try to simplify code (after applying the rewrite rule, if any).
-w
Do not print reformatted sources to standard output.
If a file's formatting is different from gofmt's, overwrite it
with gofmt's version. If an error occurred during overwriting,
the original file is restored from an automatic backup.gofmt يستخدم tab للمسافة البادئة، ومسافات للمحاذاة، افتراضياً سيُخرج الكود المنسق إلى المخرج القياسي، وليس الكتابة فوق الملف الأصلي. أمر go fmt في الواقع يستخدم أمر gofmt، وهو ملف ثنائي مستقل، موجود في دليل GOROOT/bin.
$ ls $GOROOT/bin -1
go.exe*
gofmt.exe*أضف علامة -n لأمر go fmt لمعرفة التعليمات التي سيتم تنفيذها.
$ go fmt main.go
/golang/bin/gofmt.exe -l -w main.goيمكن ملاحظة أن go fmt هو في الواقع اسم مستعار لـ gofmt -l -w، أمر gofmt لديه المعاملات التالية
-d: إخراج اختلافات الملف قبل وبعد التنسيق-e: إخراج جميع الأخطاء-l: إخراج أسماء الملفات المتغيرة-r: تطبيق قواعد التنسيق-s: محاولة تبسيط الكود-w: الكتابة فوق الملف المصدر، إذا حدث خطأ سيتم استعادة النسخة الاحتياطية
لنفترض أن لدينا الآن الملف المصدر التالي
$ cat main.go
package main
import "fmt"
func main() {
fmt.Println("hello world!")}من خلال المعامل -d يمكن معاينة التغييرات
$ gofmt -d main.go
diff main.go.orig main.go
--- main.go.orig
+++ main.go
@@ -3,5 +3,5 @@
import "fmt"
func main() {
-fmt.Println("hello world!")}
-
+ fmt.Println("hello world!")
+}المعامل -l سيُخرج اسم الملف الذي سيتم تعديله
$ gofmt -l .
main.goإذا كانت هناك أخطاء نحوية، المعامل -e يمكن أن يُخرج بمزيد من التفاصيل
$ gofmt -d -e main.go
main.go:6:27: missing ',' in argument list
main.go:6:28: expected operand, found newline
main.go:7:2: expected ')', found 'EOF'
main.go:7:2: expected ';', found 'EOF'
main.go:7:2: expected ';', found 'EOF'
main.go:7:2: expected '}', found 'EOF'
main.go:7:2: missing ',' in argument list-w سيُطبّق التعديلات على الملف المصدر
$ gofmt -l -w .
main.go
$ cat main.go
package main
import "fmt"
func main() {
fmt.Println("hello world!")
}يمكنك أن تكتشف أن كأداة تنسيق، gofmt لا يوفر تماماً أي تكوين مخصص، بينما أداة التنسيق prettify المصممة لتجميل كود js توفر الكثير من التكوينات لتنسيق الكود، هذا يعكس موقف go الرسمي، لا تفكر في التخصيص، الأفضل أن يكون نمط كود الجميع متسقاً، على الأقل هناك فائدة واحدة وهي عدم الحاجة للتكيف مع عادات الآخرين عند قراءة الكود. لكن في الواقع هي لا تزال تحتفظ بخيار تخصيص واحد، وهو قواعد استبدال تنسيق الكود، القواعد يمكن تخصيصها، التنسيق كالتالي
pattern -> replacementمثل إزالة الأقواس الزائدة
(a) -> aعرض تغييرات الملف
$ gofmt -r "(a) -> a" -d -l .
main.go
diff main.go.orig main.go
--- main.go.orig
+++ main.go
@@ -3,5 +3,5 @@
import "fmt"
func main() {
- fmt.Println(("hello world!"))
+ fmt.Println("hello world!")
}يمكنك أن ترى أن gofmt سيحذف الأقواس الزائدة.
get
أمر get هو بالتأكيد الأكثر استخداماً في تطوير go، وظيفته هي تنزيل الكود المصدري لعنوان الحزمة المحدد إلى الدليل المقابل لـ GOMODCACHE.
$ go get -h
usage: go get [-t] [-u] [-v] [build flags] [packages]
Run 'go help get' for details.-u: محاولة تحديث الإصدار الفرعي وإصدار التصحيح للحزمة، إذا كان هناك تغيير في الإصدار الرئيسي، مثلv1->v2، لن يتم التحديث.-t: تحديث إصدارات التبعيات في الاختبارات-v: إخراج الحزم المُجمّعة، في الواقع ينتمي إلى معاملاتbuild flags
في الأيام القديمة، كانت وظيفة go get مشابهة لـ go install، كانت تنزل وتُجمّع هذه الحزم، ومع ظهور ونضوج وحدات go، تم إهمال هذا الجزء من الوظيفة تدريجياً، الآن الاستخدام الأكثر شيوعاً لأمر get هو تنزيل وتحليل التبعيات لوحدات go، لذلك يمكنك أن ترى أن أمر go get يدعم أيضاً build flags، وإذا حاولت استخدامه مثل go install خارج الوحدة، سيُذكّرك أن هذا الاستخدام تم إهماله.
$ go get github.com/wire/wire
go: go.mod file not found in current directory or any parent directory.
'go get' is no longer supported outside a module.
To build and install a command, use 'go install' with a version,
like 'go install example.com/cmd@latest'
For more information, see https://golang.org/doc/go-get-install-deprecation
or run 'go help get' or 'go help install'.أما لماذا لا يزال محفوظاً في وصف التوثيق فغير معروف، بالرجوع إلى الكود المصدري لأمر get، ستجد أيضاً أنه يحتفظ بتلك العلامات القديمة.
var (
getD = CmdGet.Flag.Bool("d", true, "")
getF = CmdGet.Flag.Bool("f", false, "")
getFix = CmdGet.Flag.Bool("fix", false, "")
getM = CmdGet.Flag.Bool("m", false, "")
getT = CmdGet.Flag.Bool("t", false, "")
getU upgradeFlag
getInsecure = CmdGet.Flag.Bool("insecure", false, "")
// -v is cfg.BuildV
)بالعودة إلى الموضوع، أمر get سيُنزّل الكود المصدري للحزمة المحددة إلى دليل التبعيات العالمي المحلي، أي الدليل المقابل لـ GOCACHE، ثم يسجل المعلومات في ملفي go.mod و go.sum، الأول مسؤول عن تسجيل الإصدار، والثاني مسؤول عن تسجيل المجموع الاختباري sha1 لضمان الأمان. أمر get في الواقع مبني على VCS، أي نظام التحكم في الإصدار المحلي، يدعم الإجمالي ما يلي
- git
- hg (Mercurial)
- bzr (Bazaar)
- svn
- fossil
من بينها، الافتراضي يدعم فقط git و hg، يمكن التكوين في GOVCS، التنسيق كالتالي
GOVCS=github.com:git,example.com:hg,*:git|hg,*:allGOVCS يدعم فقط git و hg كـ VCS، الثلاثة الآخرون يحتاجون للتكوين في GOPRIVATE.
go get لديه عدة طرق استخدام إجمالاً، يمكن تمرير عنوان التبعية مباشرة كمعامل
$ go get golang.org/x/netيمكن أيضاً تحديد الإصدار
$ go get golang.org/x/net@0.17.0تحديد أحدث إصدار
$ go get golang.org/x/net@latestمحاولة تحديث الإصدار
$ go get -u golang.org/x/netإزالة تبعية معينة
$ go get golang.org/x/net@noneهذه الاستخدامات لإدارة التبعيات العادية، يمكن أيضاً استخدامه لإدارة التبعيات غير العادية، مثل تحديث إصدار لغة go
$ go get go@latest
go: updating go.mod requires go >= 1.21.3; switching to go1.21.3
go: downloading go1.21.3 (windows/amd64)
go: upgraded go 1.21.0 => 1.21.3يمكن حتى استخدامه لتحديث إصدار سلسلة أدوات go
$ go get toolchain@latestعند استخدام go get لتحديث إصدارات go وسلسلة الأدوات، سيتم تثبيت الإصدار الجديد من go في دليل GOMODCACHE/golang.org/
$ ls $(go env GOMODCACHE)/golang.org -1
'toolchain@v0.0.1-go1.21.3.windows-amd64'/
x/في هذه الحالة يمكنك تعديل GOROOT يدوياً للتبديل إلى الإصدار المحدد.
install
أمر install مشابه لأمر get، كلاهما يُستخدم لتنزيل التبعيات الخارجية، لكن الفرق هو أن أمر get ينزل الكود المصدري، بينما أمر install سيُجمّع الكود المصدري إلى ملف ثنائي قابل للتنفيذ على الجهاز، مسار تخزين الملف الثنائي أولاً في دليل GOBIN، ثم في GOPATH/bin. الوظيفة الرئيسية لهذا الأمر هي تنزيل بعض أدوات سطر الأوامر الخارجية المفتوحة، وبفضل سرعة تجميع لغة go وقابليتها للنقل، لا تحتاج لتنزيل الملفات الثنائية، بل تنزيل الكود المصدري مباشرة ثم تجميعه محلياً.
$ go install -h
usage: go install [build flags] [packages]
Run 'go help install' for details.أمر install يقبل علامات البناء واسم الحزمة كمعاملات، في حالة تفعيل gomod، يجب أن يحمل اسم الحزمة رقم الإصدار. مثلاً تنزيل مصحح الأخطاء delve
$ go install -x github.com/go-delve/delve/cmd/dlv@latest
# get https://goproxy.cn/github.com/@v/list
# get https://goproxy.cn/github.com/go-delve/delve/cmd/@v/list
# get https://goproxy.cn/github.com/go-delve/delve/cmd/dlv/@v/list
# get https://goproxy.cn/github.com/go-delve/delve/@v/list
# get https://goproxy.cn/github.com/go-delve/@v/list
# get https://goproxy.cn/github.com/@v/list: 404 Not Found (0.014s)
# get https://goproxy.cn/github.com/go-delve/delve/cmd/@v/list: 404 Not Found (0.027s)
# get https://goproxy.cn/github.com/go-delve/delve/cmd/dlv/@v/list: 404 Not Found (0.027s)
# get https://goproxy.cn/github.com/go-delve/delve/@v/list: 200 OK (0.027s)
# get https://goproxy.cn/github.com/go-delve/@v/list: 404 Not Found (0.027s)
WORK=/home/user/tmp/go-build2033992495
mkdir -p $WORK/b001/
cat >/home/user/tmp/go-build2033992495/b001/importcfg.link << 'EOF' # internal
packagefile github.com/go-delve/delve/cmd/dlv=/home/user/.cache/go-build/f1/f11d552287458c0fce625abe50bf928c487064c36bbb1251ad8b1968772c3e4b-d
......
......
mkdir -p /home/wyh/gomod/bin/
mv $WORK/b001/exe/a.out /home/wyh/gomod/bin/dlv
rm -r $WORK/b001/أولاً سيُنزّل الكود المصدري إلى المسار المخزن في GOMODCACHE، وهذا مشابه لأمر get، ثم ينتقل إلى دليل العمل المؤقت، ويُجمّعه، بعد اكتمال التجميع ينقل الملف الثنائي إلى دليل GOPATH/bin، وأخيراً يحذف المجلد المؤقت. أمر install له قيد آخر وهو أن الحزمة المنزلة يجب أن تكون حزمة مدخل المشروع، أي يجب أن تحتوي على ملف مدخل main.go، وإلا سيُذكّرك أنه لا يمكن تثبيتها. مثلاً، استخدام go install لتنزيل gin
$ go install -x github.com/gin-gonic/gin@latest
# get https://goproxy.cn/github.com/@v/list
# get https://goproxy.cn/github.com/gin-gonic/gin/@v/list
# get https://goproxy.cn/github.com/gin-gonic/@v/list
# get https://goproxy.cn/github.com/@v/list: 404 Not Found (0.022s)
# get https://goproxy.cn/github.com/gin-gonic/gin/@v/list: 200 OK (0.027s)
# get https://goproxy.cn/github.com/gin-gonic/@v/list: 404 Not Found (0.028s)
package github.com/gin-gonic/gin is not a main packagegin هو مكتبة تبعية إطار عمل web، وليس أداة سطر أوامر، وبطبيعة الحال ليس لديه ملف مدخل، لذا سيفشل التثبيت.
list
أمر list سيُخرج قائمة الحزم في الموقع المحدد، واحدة في كل سطر، ويدعم تنسيق الإخراج المخصص، ويدعم العديد من المعاملات، شرط استخدامه هو أن تكون في مشروع يدعم gomod.
$ go list -h
usage: go list [-f format] [-json] [-m] [list flags] [build flags] [packages]
Run 'go help list' for details.يدعم المعاملات التالية
-f: معامل التنسيق-json: إخراج بصيغة json-compiled: عرض جميع الحزم التي سيُجمّعها المجمع-deps: عرض اسم كل حزمة وكل تبعياتها-test: عرض حزمة الاختبار لكل حزمة-e: الإخراج بشكل طبيعي عند مواجهة حزم بها أخطاء-find: عدم تحليل علاقات التبعية لهذه الحزم-export: عند استخدام هذا المعامل، تعيين قيمة حقلPackage.Exportللهيكل إلى الملف الذي يحتوي على أحدث معلومات تصدير للحزمة المحددة، وتعيين قيمة حقلPackage.BuildIDإلىBuildIDللحزمة، يستخدم بشكل أساسي لتنسيق الإخراج.
معاملات معلومات الوحدة،
-m: إخراج الوحدة بدلاً من إخراج الحزمة-versions: عرض جميع المعلومات المتاحة لوحدة-retracted: عرض الإصدار المسحوب لوحدة
المعامل [packages] يمكن أن يكون اسم حزمة محدد، أو مجلد، أو all، يعني أي مكان، عند استخدام المعامل -m، يعني all جميع التبعيات المُشار إليها في الوحدة الحالية.
مثلاً، الملف الحالي يحتوي فقط على ملف main.go، وكود واحد فقط يُخرج "hello world"، بعد تنفيذ go list -deps .، سيُخرج جميع الحزم من المشروع الحالي إلى fmt وجميع التبعيات المُشار إليها.
$ ls
go.mod go.sum main.go
$ cat main.go
package main
import "fmt"
func main() {
fmt.Println("hello world")
}
$ go list -deps .
internal/goarch
unsafe
internal/abi
internal/unsafeheader
internal/cpu
internal/bytealg
internal/coverage/rtcov
internal/godebugs
internal/goexperiment
internal/goos
runtime/internal/atomic
runtime/internal/math
runtime/internal/sys
runtime
......
......
path
io/fs
os
fmt
golearnأو إخراج جميع تبعيات الوحدة في المشروع الحالي
$ go list -m all
golearn
cloud.google.com/go v0.26.0
github.com/246859/containers v0.0.1
github.com/246859/river v0.1.0 => D:\WorkSpace\Code\riverdb
github.com/BurntSushi/toml v0.3.1
github.com/Jleagle/steam-go v0.0.0-20230725082712-1053b441b1f2
github.com/Jleagle/unmarshal-go v0.0.0-20210227002040-694f544f9265
github.com/KyleBanks/depth v1.2.1
github.com/Microsoft/go-winio v0.6.1
github.com/PuerkitoBio/purell v1.1.1
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578
github.com/andeya/ameda v1.5.3
github.com/andeya/goutil v1.0.1
...format
إخراج أمر list يكون على شكل أسطر، كل سطر هو حزمة. يوفر المسؤول معاملاً f- يمكننا من تخصيص تنسيق إخراج السطر، القيمة التي يقبلها هي صيغة القالب المحددة بواسطة محرك القوالب template/text، مثل المثال التالي
-f "package {{ .Dir }} {{ .Name }}"كل حزمة مُكرّر عليها ستُمرّر على شكل الهيكل التالي، جميع الحقول في هذا الهيكل يمكن استخدامها كمعاملات للقالب.
type Package struct {
Dir string // directory containing package sources
ImportPath string // import path of package in dir
ImportComment string // path in import comment on package statement
Name string // package name
Doc string // package documentation string
Target string // install path
Shlib string // the shared library that contains this package (only set when -linkshared)
Goroot bool // is this package in the Go root?
Standard bool // is this package part of the standard Go library?
Stale bool // would 'go install' do anything for this package?
StaleReason string // explanation for Stale==true
Root string // Go root or Go path dir containing this package
ConflictDir string // this directory shadows Dir in $GOPATH
BinaryOnly bool // binary-only package (no longer supported)
ForTest string // package is only for use in named test
Export string // file containing export data (when using -export)
BuildID string // build ID of the compiled package (when using -export)
Module *Module // info about package's containing module, if any (can be nil)
Match []string // command-line patterns matching this package
DepOnly bool // package is only a dependency, not explicitly listed
DefaultGODEBUG string // default GODEBUG setting, for main packages
// Source files
GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
CgoFiles []string // .go source files that import "C"
CompiledGoFiles []string // .go files presented to compiler (when using -compiled)
IgnoredGoFiles []string // .go source files ignored due to build constraints
IgnoredOtherFiles []string // non-.go source files ignored due to build constraints
CFiles []string // .c source files
CXXFiles []string // .cc, .cxx and .cpp source files
MFiles []string // .m source files
HFiles []string // .h, .hh, .hpp and .hxx source files
FFiles []string // .f, .F, .for and .f90 Fortran source files
SFiles []string // .s source files
SwigFiles []string // .swig files
SwigCXXFiles []string // .swigcxx files
SysoFiles []string // .syso object files to add to archive
TestGoFiles []string // _test.go files in package
XTestGoFiles []string // _test.go files outside package
// Embedded files
EmbedPatterns []string // //go:embed patterns
EmbedFiles []string // files matched by EmbedPatterns
TestEmbedPatterns []string // //go:embed patterns in TestGoFiles
TestEmbedFiles []string // files matched by TestEmbedPatterns
XTestEmbedPatterns []string // //go:embed patterns in XTestGoFiles
XTestEmbedFiles []string // files matched by XTestEmbedPatterns
// Cgo directives
CgoCFLAGS []string // cgo: flags for C compiler
CgoCPPFLAGS []string // cgo: flags for C preprocessor
CgoCXXFLAGS []string // cgo: flags for C++ compiler
CgoFFLAGS []string // cgo: flags for Fortran compiler
CgoLDFLAGS []string // cgo: flags for linker
CgoPkgConfig []string // cgo: pkg-config names
// Dependency information
Imports []string // import paths used by this package
ImportMap map[string]string // map from source import to ImportPath (identity entries omitted)
Deps []string // all (recursively) imported dependencies
TestImports []string // imports from TestGoFiles
XTestImports []string // imports from XTestGoFiles
// Error information
Incomplete bool // this package or a dependency has an error
Error *PackageError // error loading package
DepsErrors []*PackageError // errors loading dependencies
}
type PackageError struct {
ImportStack []string // shortest path from package named on command line to this one
Pos string // position of error (if present, file:line:col)
Err string // the error itself
}إذا كان المُكرّر عليه هو وحدة، فسيُمرّر على شكل الهيكل التالي، جميع حقوله يمكن أيضاً استخدامها كمعاملات للقالب.
type Module struct {
Path string // module path
Query string // version query corresponding to this version
Version string // module version
Versions []string // available module versions
Replace *Module // replaced by this module
Time *time.Time // time version was created
Update *Module // available update (with -u)
Main bool // is this the main module?
Indirect bool // module is only indirectly needed by main module
Dir string // directory holding local copy of files, if any
GoMod string // path to go.mod file describing module, if any
GoVersion string // go version used in module
Retracted []string // retraction information, if any (with -retracted or -u)
Deprecated string // deprecation message, if any (with -u)
Error *ModuleError // error loading module
Origin any // provenance of module
Reuse bool // reuse of old module info is safe
}
type ModuleError struct {
Err string // the error itself
}عرض جميع الحزم
$ go list -f "package {{.Dir}} {{.Name}}" ./...
package /golearn main
package /golearn/app cmd
package /golearn/cmd cmd
package /golearn/docs docs
package /golearn/tool tool
package /golearn/tool_test toolعرض الوحدات
$ go list -m -f "mod {{.Path}} {{.Version}} {{.GoVersion}} {{.GoMod}}"
mod golearn 1.21.3 /golearn/go.modmod
go mod هو أمر مخصص لإدارة وحدات go.
$ go mod help
Go mod provides access to operations on modules.
Note that support for modules is built into all the go commands,
not just 'go mod'. For example, day-to-day adding, removing, upgrading,
and downgrading of dependencies should be done using 'go get'.
See 'go help modules' for an overview of module functionality.
Usage:
go mod <command> [arguments]
The commands are:
download download modules to local cache
edit edit go.mod from tools or scripts
graph print module requirement graph
init initialize new module in current directory
tidy add missing and remove unused modules
vendor make vendored copy of dependencies
verify verify dependencies have expected content
why explain why packages or modules are needed
Use "go help mod <command>" for more information about a command.له الأوامر الفرعية التالية
download: تنزيل جميع التبعيات المُشار إليها في ملفgo.modإلى الذاكرة المؤقتة المحليةedit: تعديل ملفgo.mod، الواجهة التي يوفرها سطر الأوامر مخصصة بشكل أساسي للأدوات أو النصوص البرمجية الأخرى لاستدعائها.init: تهيئة مشروع gomod في الدليل الحاليtidy: تنزيل التبعيات المفقودة، حذف التبعيات غير المستخدمةgraph: إخراج رسم التبعياتverify: التحقق من التبعيات المحليةwhy: شرح سبب الحاجة إلى هذه الوحداتvendor: تصدير تبعيات المشروع إلى دليل vendor
init
$ go help mod init
usage: go mod init [module-path]أمر init يُستخدم لتهيئة مشروع gomod، معامله الوحيد هو مسار الوحدة، الذي سيكون الأساس للآخرين لتنزيل تبعياتك في المستقبل. قواعد تسميته عموماً هي
domain_name/user_name/repo_nameمثل أن الناس عموماً يضعون مشاريعهم على github، لذا يمكن أن يكون
github.com/jack/gotourلا يُنصح باستخدام رموز خاصة في مسار الوحدة. إليك حالة استخدام
$ mkdir gotour
$ cd gotour
$ go mod init "github.com/jack/gotour"
go: creating new go.mod: module github.com/jack/gotourtidy
$ go help mod tidy
usage: go mod tidy [-e] [-v] [-x] [-go=version] [-compat=version]أمر tidy سيُنظّف التبعيات غير المفيدة في go.mod، أي التبعيات غير المُشار إليها، وسيُنزّل التبعيات المُشار إليها لكن غير الموجودة. يدعم المعاملات التالية
-v، إخراج تبعيات الوحدات المحذوفة-e، إذا حدث خطأ أثناء العملية تجاهله واستمر في التنفيذ-x، إخراج عملية التنفيذ-go=version، تحديث إصدار go في ملفgo.mod-compact=version، الاحتفاظ بأي مجاميع اختبارية إضافية مطلوبة من إصدار Go الرئيسي المحدد لتحميل رسم الوحدة بنجاح، وإذا كان إصدارgoسيحمّل أي حزم مستوردة من إصدارات وحدة مختلفة، فسيؤدي ذلك إلى خطأ في tidy. عادةً ما يُستخدم هذا المعامل نادراً، وعموماً يحدث خطأ فقط عند تغيير الإصدار، يمكنك الذهاب إلى stackoverflow لرؤية هذا الإجابة go modules - go mod tidy error message: "but go 1.16 would select" - Stack Overflow
انظر مثال استخدام
$ go mod tidy -v
unused github.com/246859/containers
unused github.com/246859/river
unused github.com/Jleagle/steam-go
unused github.com/Jleagle/unmarshal-go
unused github.com/KyleBanks/depth
unused github.com/Microsoft/go-winio
unused github.com/PuerkitoBio/purell
unused github.com/PuerkitoBio/urlesc
unused github.com/andeya/ameda
unused github.com/andeya/goutil
unused github.com/asaskevich/govalidator
unused github.com/buger/jsonparser
unused github.com/bwmarrin/snowflake
unused github.com/bytedance/go-tagexpr/v2
unused github.com/bytedance/sonic
unused github.com/cespare/xxhash/v2
unused github.com/chenzhuoyu/base64x
......download
$ go help mod download
usage: go mod download [-x] [-json] [-reuse=old.json] [modules]اسم أمر download وإن كان يعني التنزيل عند الترجمة، لكنه فقط يُنزّل التبعيات إلى الذاكرة المؤقتة المحلية للملفات، ولا يُعدّل ملف go.mod، وظيفته هي التنزيل المسبق للتبعيات إلى الذاكرة المؤقتة المحلية للملفات، إذا كنت تريد تنزيل تبعية معينة، يُنصح باستخدام go get أو go mod tidy.
فيما يلي بعض أمثلة الاستخدام
$ go mod download -x gorm.io/gorm
# get https://goproxy.cn/gorm.io/gorm/@v/list
# get https://goproxy.cn/gorm.io/gorm/@v/list: 200 OK (0.084s)إذا تم تنفيذه بدون أي معاملات، سيُنزّل جميع التبعيات الموجودة في ملف go.mod وغير الموجودة في الذاكرة المؤقتة المحلية للتبعيات، إذا لم يكن هناك ما يحتاج للتنزيل سيُخرج
go: no module dependencies to downloadedit
$ go help mod edit
usage: go mod edit [editing flags] [-fmt|-print|-json] [go.mod]edit هو واجهة سطر أوامر لتعديل ملف go.mod، عادةً ما تكون مخصصة للاستخدام من قبل برامج أخرى، بعض المحررات IDE توفر دعم gomod باستخدام هذه الأوامر. يدعم المعاملات التالية
-module، تعديل مسار الوحدة-go=version، تعديل إصدار go المتوقع-require=path@version، إضافة تبعية جديدة-droprequire=path@version، حذف تبعية-exclude=path@version، إضافة تبعية مستثناة-dropexclude=path@version، حذف تبعية مستثناة-replace=old@version=new@version، إضافة تبعية بديلة-dropreplace=old@version، حذف تبعية بديلة-retract=version، إضافة عنصر تراجع عن إصدار-dropretract=version، حذف عنصر تراجع عن إصدار
هناك أيضاً بعض المعاملات الأخرى للعرض
-print، إخراج محتوى الملف-json، الإخراج بصيغة json
مثل المثال التالي
$ go mod edit -print
module golearn
go 1.21.3
require (
github.com/dstgo/task v1.2.0
github.com/spf13/cast v1.5.1
github.com/swaggo/swag v1.16.2
golang.org/x/net v0.19.0
gorm.io/gorm v1.25.5
)graph
$ go help mod graph
usage: go mod graph [-go=version] [-x]أمر graph سيُخرج رسم التبعيات في المشروع الحالي، قابلية قراءته ضعيفة، ومعظم الأوقات ليس للبشر قراءته، نتائجه عادةً ما تُعالج ثم تُعرض بشكل مرئي. كل سطر هو تبعية، تنسيقه كالتالي
المرجع المُشار إليه المُشار إليهمثل
golearn go@1.21.3يدعم أيضاً معاملين
-go=version، تحميل رسم التبعيات باستخدام إصدار go المحدد، قيمته لا يمكن أن تكون أقل من الإصدار في ملفgo.mod.-x، عرض الأوامر المنفذة أثناء العملية.
انظر مثال استخدام بسيط
$ go mod graph
golearn github.com/246859/containers@v0.0.1
golearn github.com/246859/river@v0.1.0
golearn github.com/Jleagle/steam-go@v0.0.0-20230725082712-1053b441b1f2
golearn github.com/Jleagle/unmarshal-go@v0.0.0-20210227002040-694f544f9265
golearn github.com/KyleBanks/depth@v1.2.1
golearn github.com/Microsoft/go-winio@v0.6.1
golearn github.com/PuerkitoBio/purell@v1.1.1
golearn github.com/PuerkitoBio/urlesc@v0.0.0-20170810143723-de5bf2ad4578
golearn github.com/andeya/ameda@v1.5.3
golearn github.com/andeya/goutil@v1.0.1
golearn github.com/asaskevich/govalidator@v0.0.0-20230301143203-a9d515a09cc2
golearn github.com/buger/jsonparser@v1.1.1
golearn github.com/bwmarrin/snowflake@v0.3.0
golearn github.com/bytedance/go-tagexpr/v2@v2.9.11
......vendor
$ go help mod vendor
usage: go mod vendor [-e] [-v] [-o outdir]vendor هو حل بديل لـ gopath في الأيام الأولى قبل إصدار gomod، كل مشروع go كان لديه دليل vendor، يُخزن كل تبعية المشروع بشكل منفصل بتنسيق domain/user/project، مثل node_module المنتفخ في nodeJs المجاور، كل مشروع تبعياته مُخزنة بشكل منفصل، طريقة إدارة التبعيات هذه تبدو غبية الآن، لكن في ذلك الوقت لم يكن هناك حل أفضل، السبب في الاحتفاظ بـ vendor هو أن go يلتزم بوعد التوافق مع الإصدارات السابقة، بعض المشاريع القديمة بما فيها الكود المصدري لـ go قد لا تزال تستخدم vendor.
بالعودة إلى الموضوع، vendor هو أمر فرعي لـ go mod، يمكنه تصدير التبعيات العالمية المُشار إليها في الوحدة الحالية إلى دليل vendor.
$ go mod vendor -h
usage: go mod vendor [-e] [-v] [-o outdir]
Run 'go help mod vendor' for details.له المعاملات التالية
-o: تحديد مسار مجلد الإخراج-v: إخراج كل تبعية-e: الاستمرار عند حدوث خطأ
انظر مثالاً، أولاً استخدم go list -m all لعرض التبعيات المُشار إليها في المشروع الحالي
$ go list -m all
github.com/dstgo/task
github.com/davecgh/go-spew v1.1.1
github.com/pkg/errors v0.9.1
github.com/pmezard/go-difflib v1.0.0
github.com/stretchr/objx v0.5.0
github.com/stretchr/testify v1.8.4
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405
gopkg.in/yaml.v3 v3.0.1التصدير إلى دليل vendor الحالي
$ go mod vendor -v -e -o vendor
# github.com/davecgh/go-spew v1.1.1
## explicit
github.com/davecgh/go-spew/spew
# github.com/pkg/errors v0.9.1
## explicit
github.com/pkg/errors
# github.com/pmezard/go-difflib v1.0.0
## explicit
github.com/pmezard/go-difflib/difflib
# github.com/stretchr/testify v1.8.4
## explicit; go 1.20
github.com/stretchr/testify/assert
# gopkg.in/yaml.v3 v3.0.1
## explicit
gopkg.in/yaml.v3هيكل الدليل بعد التصدير كالتالي
└─vendor
├─github.com
│ ├─davecgh
│ │ └─go-spew
│ │ └─spew
│ ├─pkg
│ │ └─errors
│ ├─pmezard
│ │ └─go-difflib
│ │ └─difflib
│ └─stretchr
│ └─testify
│ └─assert
└─gopkg.in
| └─yaml.v3
|
|--modules.txtمن بينها modules.txt هو ملف يصف جميع التبعيات، مشابه لـ go.mod الحالي.
verify
$ go help mod verify
usage: go mod verifyهذا الأمر سيتحقق مما إذا كانت تبعيات المشروع قد تم تعديلها منذ تنزيلها إلى المحلي. مثل، إذا لم تكن هناك مشاكل سيُخرج all modules verified
$ go mod verify
all modules verifiedوإلا سيُبلغ عن أين حدث التغيير، وينتهي الأمر بحالة غير طبيعية. مثل
$ go mod verify
gorm.io/gorm v1.25.5: dir has been modified (/go/mod/libs/gorm.io/gorm@v1.25.5)why
$ go help mod why
usage: go mod why [-m] [-vendor] packages...يشرح سبب الحاجة إلى هذه الحزمة، في الواقع يُخرج رسم التبعيات المتعلق بها. مثل
$ go mod why gorm.io/gorm
# gorm.io/gorm
golearn
gorm.io/gormالافتراضي هو فقط تحليل الاستيراد من main، إضافة المعامل -m يمكن تحليل حالة استيراد كل حزمة.
work
أمر work هو أداة تطوير محلية لإدارة وحدات go المتعددة
$ go work help
Work provides access to operations on workspaces.
Note that support for workspaces is built into many other commands, not
just 'go work'.
The commands are:
edit edit go.work from tools or scripts
init initialize workspace file
sync sync workspace build list to modules
use add modules to workspace file
vendor make vendored copy of dependencies
Use "go help work <command>" for more information about a command.init
الأمر الفرعي init يُستخدم لتهيئة مساحة عمل، هذا الأمر سيُنشئ ملفاً اسمه go.work
$ go work init -h
usage: go work init [moddirs]
Run 'go help work init' for details.يقبل المعامل [moddirs] لتحديد أدلة الوحدات التي ستُدرج في الإدارة، مثل
$ go work init ./service ./apiuse
الأمر الفرعي use يُستخدم لإضافة أدلة الوحدات المُدرجة في الإدارة إلى go.work
$ go help work use
usage: go work use [-r] [moddirs]
Use provides a command-line interface for adding
directories, optionally recursively, to a go.work file.يقبل [moddirs] كمعامل، وهناك أيضاً -r يعني البحث المتكرر عن الوحدات في مسار [moddirs]، مثل
$ go work use -r ./oss-api ./multi_modulesedit
وظيفة الأمر الفرعي edit هي نفسها go mod edit، كلاهما يترك واجهة سطر أوامر للأدوات والنصوص البرمجية الأخرى للعمل عليها.
$ go help work edit
usage: go work edit [editing flags] [go.work]
Edit provides a command-line interface for editing go.work,
for use primarily by tools or scripts. It only reads go.work;
it does not look up information about the modules involved.
If no file is specified, Edit looks for a go.work file in the current
directory and its parent directoriesالمعاملات كالتالي
-fmt، تنسيق ملفgo.work-use،-dropuse، إضافة وإزالة مسارات الوحدات-replace=old[@v]=new[@v]،-dropreplace=old[@v]=new[@v]، لإضافة وإزالة الوحدات المراد استبدالها-go،-toolchain=name، تحديد إصدار go، وتحديد سلسلة الأدوات المراد استخدامها-print، طباعة التعديلات النهائية، لا تُكتب إلى الملف-json، الإخراج بصيغةjson، لا يمكن أن يتواجد مع-print، النوع المقابل كالتاليgotype GoWork struct { Go string Toolchain string Use []Use Replace []Replace } type Use struct { DiskPath string ModulePath string } type Replace struct { Old Module New Module } type Module struct { Path string Version string }
بعض أمثلة الاستخدام كالتالي، تنسيق الإخراج
$ go work edit -fmt -print
go 1.22.0
use (
./ab/cd
./auth
./user
)إخراج json
$ go work edit -fmt -json
{
"Go": "1.22.0",
"Use": [
{
"DiskPath": "./ab/cd"
},
{
"DiskPath": "./auth"
},
{
"DiskPath": "./user"
}
],
"Replace": null
}sync
الأمر الفرعي sync يُستخدم لإعادة قائمة بناء workspace في go.work إلى الوحدات المختلفة في workspace.
$ go help work sync
usage: go work sync
Sync syncs the workspace's build list back to the
workspace's modulesهذه العملية تحدث بشكل رئيسي بعد اكتمال التطوير المحلي، عندما اكتملت أعمال النشر لكل وحدة، في هذه الحالة استخدام sync، سيُحدّث تبعيات go.mod لجميع الوحدات في worksapce بناءً على علاقات التبعية بين الوحدات، وبذلك لا نحتاج للتحديث يدوياً.
vendor
أمر vendor سيُنشئ نسخة من جميع مكتبات التبعيات للوحدات في workspace في دليل vendor.
$ go work help vendor
usage: go work vendor [-e] [-v] [-o outdir]وظيفته نفس go mod vendor، لن نقدم الكثير من التفاصيل.
vet
أمر vet هو أداة فحص أخطاء ثابتة للكود المصدري للغة go، مثل أدوات lint في اللغات الأخرى، مثل Eslint.
$ go vet -h
usage: go vet [build flags] [-vettool prog] [vet flags] [packages]
Run 'go help vet' for details.
Run 'go tool vet help' for a full list of flags and analyzers.
Run 'go tool vet -help' for an overview.لنبدأ بمثال بسيط، لدينا الكود المصدري التالي
$ cat main.go
package main
import "fmt"
func main(){
fmt.Println("hello world!"
}تنفيذ go vet بدون أي معاملات في نفس الدليل
$ go vet
vet: ./main.go:6:28: missing ',' before newline in argument list (and 1 more errors)vet سيُبلغ عن أي ملف وأي سطر به مشكلة. يدعم علامات البناء كمعاملات، مثل -n و -x، ويدعم الحزم، المجلدات، أسماء الملفات كمعاملات.
$ go vet .
$ go vet main.go
$ go vet ./cmd
$ go vet runtimeمن خلال الأمر التالي لعرض معاملاته وتفسيراته الأكثر تفصيلاً.
$ go tool vet help
vet is a tool for static analysis of Go programs.
vet examines Go source code and reports suspicious constructs,
such as Printf calls whose arguments do not align with the format
string. It uses heuristics that do not guarantee all reports are
genuine problems, but it can find errors not caught by the compilers.
Registered analyzers:
asmdecl report mismatches between assembly files and Go declarations
assign check for useless assignments
atomic check for common mistakes using the sync/atomic package
bools check for common mistakes involving boolean operators
buildtag check //go:build and // +build directives
......أمر go tool vet لا يمكن استخدامه مباشرة لفحص الكود، يجب استخدام go vet. المعامل [vet flag] في go vet يدعم إعداد محلل الكود، القيم المتاحة كالتالي
asmdecl 检查汇编文件是否与go声明不匹配
assign 检查是否有无用的变量
atomic 检查使用sync/atomic时是否破坏了原子性
bools 检查是否错误使用逻辑运算符
buildtag 检查build tag
cgocall 检查违反cgao指针传递规则的行为
composites 检查未初始化的复合结构,比如map,chan
copylocks 检查是否发生了锁的值复制
directive 检查go工具链指令
errorsas 检查是否向errors.As传递非指针类型或非error类型的值
framepointer 检查编译优化后的汇编代码是否在保存帧指针之前对其进行清除
httpresponse 检查是否错误使用httpresponse
ifaceassert 检查接口到接口的类型断言
loopclosure 循环变量的引用问题
lostcancel context.WithCancel没有使用cancel函数
nilfunc 检查函数和nil之间是否存在无用的比较
printf 检查printf的格式化参数是否正确
shift 检查是否有等于或超过整数宽度的移位
sigchanyzer 检查无缓冲的chan os.Signal
slog 检查不合法的结构化日志调用
stdmethods 检查已知接口方法的签名是否正确
stringintconv 检查字符串整型转换
structtag 检查结构体tag是否正确
testinggoroutine 检查是否在测试中使用协程调用testing.Fatal
tests 检查测试和示例的常见错误用法
timeformat 使用(time.Time).Format 或 time.Parse的时间格式是否正确
unmarshal 向unmarshal传递非指针或非接口类型
unreachable 检查不可到达的代码
unsafeptr 检查uintptr到unsafe.Pointer不正确转换
unusedresult 检查未使用的函数返回值جميعها محللات تحلل نقطة معينة، مثل محلل timeformat يفحص ما إذا كان تنسيق استدعاء time.Format يتوافق مع الصيغة الصحيحة. افتراضياً سيتم تفعيل جميع المحللات المذكورة أعلاه، لتفعيل محلل منفصل يمكن استخدام التنسيق التالي
$ go vet -timeformat main.goللتعطيل المنفرد
$ go vet -timeformat=false main.goالكود المصدري لهذه المحللات موجود في cmd/vendor/golang.org/x/tools/go/analysis/passes، كل محلل هو فخ شائع في لغة go، لذا يُنصح بشدة باستخدام أمر vet لفحص الكود الخاص بك. بالإضافة إلى هؤلاء، يدعم أيضاً بعض علامات المعاملات الأخرى
-V، فقط طباعة الإصدار ثم الخروج-json، الإخراج بصيغة json-c=n، عرض عدد محدد من أسطر التعارض في السياق (يبدو أنه لا فائدة منه)
هناك أيضاً بعض المحللات الخارجية، مثل shadows، المسؤولة عن اكتشاف مشاكل إخفاء المتغيرات المسماة بمتغيرات قصيرة، وبما أنها خارجية فتحتاج للتنزيل باستخدام go install
$ go install golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow@latestتنسيق الاستخدام كالتالي
$ go vet -vettool=$(which shadow)test
$ go test -h
usage: go test [build/test flags] [packages] [build/test flags & test binary flags]
Run 'go help test' and 'go help testflag' for details.أمر test هو أمر يوفر وظيفة الاختبار في سلسلة أدوات لغة go، هذه الوظيفة مهمة جداً، للبرامج، الاختبار الكامل ضروري. هنا مجرد مقدمة بسيطة لكيفية استخدام أمر test، لمعرفة المزيد عن الاختبار، انتقل إلى: الاختبار
بالإضافة إلى دعم معاملات التجميع لأمر build، يدعم test أيضاً المعاملات التالية
-args، معاملات مدخل البرنامج-c، تجميع الملف الثنائي للاختبار للحزمة الحالية إلى الدليل الحالي لكن بدون تنفيذه، يُسمىpkg.test-exec، تنفيذ بعض الأوامر الأخرى قبل بدء الاختبار-json، نمط إخراج الاختبار يصبح json-o، تحديد اسم مسار الملف الثنائي للاختبار
يدعم أيضاً العديد من testflag ، استخدم أمر help لعرض جميع testflag
$ go help testflag
`go test` 命令既接受作用于 `go test` 本身的标志,
也接受作用于生成的测试二进制文件的标志。
`go test` 命令识别以下标志,并用于控制任何测试的执行:
-bench regexp
-benchtime t
-count n
......مقدمة لبعض المعاملات شائعة الاستخدام
-v، إخراج نتيجة اختبار كل حالة.-timeout duration، مهلة تنفيذ الاختبار-skip regexp، تخطي حالات الاختبار المحددة-short، تقصير وقت تشغيل حالات الاختبار التي تستغرق وقتاً طويلاً-shuffle، خلط ترتيب تنفيذ جميع حالات الاختبار-run regexp، تشغيل حالات الاختبار المحددة-list regexp،列出每一个测试用例-cpu 1,2,4، تحديد عدد cpu-count n، تحديد عدد مرات تنفيذ كل حالة اختبار
أبسط استخدام هو، بدون أي معاملات، سيُنفذ جميع حالات الاختبار في الحزمة الحالية، ويُخرج النتائج.
$ ls *_test.go
hello_test.go
$ go test
PASS
ok golearn 0.522sتحديد ملف اختبار معين
$ go test hello_test.go
ok command-line-arguments 0.041sإضافة المعامل -v يمكن عرض إخراج أكثر تفصيلاً، إنه شائع جداً.
$ go test -v hello_test.go
=== RUN TestHello
hello_test.go:6: hello world!
--- PASS: TestHello (0.00s)
PASS
ok command-line-arguments 0.041sتحديد حالة اختبار معينة
$ go test -v -run TestHello
=== RUN TestHello
hello_test.go:6: hello world!
--- PASS: TestHello (0.00s)
PASS
ok golearn 0.028sأثناء الاختبار، أمر test ينقسم إلى وضعين، أولاً وضع المجلد، عند تنفيذ أمر test بدون معامل package، سيُنفذ الاختبار في وضع المجلد، مثل الأوامر التالية
$ go test
$ go test -vفي هذا الوضع، يتم تعطيل ذاكرة الاختبار المؤقتة. الوضع الآخر هو وضع القائمة، عندما لا يكون معامل package فارغاً، سيتم الاختبار في وضع القائمة، والفرق بينه وبين السابق هو ما إذا كان سيتم تفعيل ذاكرة الاختبار المؤقتة. مثل التالي
$ go test -v .
$ go test -v ./...
$ go test .
$ go test -v net/httpفي وضع القائمة، سيقوم go بتجميع ملفات اختبار كل حزمة في الحزمة المحددة إلى ملفات ثنائية وتنفيذها، لتجنب تشغيل الاختبارات بشكل متكرر، سيقوم go افتراضياً بتخزين النتائج مؤقتاً، ولن يعيد التجميع عند التشغيل للمرة الثانية. استخدام المعاملات التالية سيُفعّل الذاكرة المؤقتة افتراضياً
-benchtime-cpu-list-parallel-runshort-timeout-failfast-v
استخدام معاملات أخرى غير هذه يمكن إيقاف الذاكرة المؤقتة، الطريقة التي يدعو إليها المسؤول هي استخدام -count=1 لتعطيل الذاكرة المؤقتة. مثل
$ go test -v -count=1 ./...التوجيهات
بخلاف الأوامر، توجيهات go موجودة في الملفات المصدرية بشكل ثابت، ولها اسم آخر أكثر اصطلاحية: توجيهات الترجمة (pragma directives).
المجمع والرابط سيغيران سلوكهما بسببها للوصول إلى التحكم في التجميع، يشبه إلى حد ما الماكرو في لغة C، وبالطبع ليست كل التوجيهات تُستخدم للتأثير على التجميع، بعضها لوظائف أخرى، مثل توجيه generate يُستخدم عادةً لوظيفة توليد الكود. هذه التوجيهات موجودة عادةً على شكل تعليقات، وبادئتها //go:، ولا يمكن أن تحتوي على أي مسافات في المنتصف، مثل توجيه //go:generate. جميع أنواع التوجيهات تنقسم إلى نوعين
- توجيهات وظيفية، هذه توجيهات وظيفية يوفرها go يمكن استخدامها بحرية، مثل
generate،embed،build. - توجيهات المجمع، هذه التوجيهات يجب استخدامها بحذر، الاستخدام العشوائي قد يؤدي إلى نتائج غير متوقعة.
باستثناء التوجيهات الوظيفية، معظم التوجيهات يمكنها فقط العمل على توقيعات الدوال. للتوجيهات المتعلقة بالمجمع يمكنك تنفيذ الأمر go doc compile لعرض توجيهاته. لجميع التوجيهات، يمكن العثور على معلومات عنها في cmd/compile/internal/ir/node.go: 440.
generate
$ go help generate
usage: go generate [-run regexp] [-n] [-v] [-x] [build flags] [file.go... | packages]توجيه generate كما يوحي اسمه له علاقة بالتوليد، عادةً وظيفته هي تنفيذ الأوامر التي تولد الكود وتُحدّث الكود المصدري، لكن في الواقع يمكنه تنفيذ أي أمر. بالإضافة إلى ذلك، توجيه generate يختلف عن التوجيهات الأخرى، له أمر مخصص يمكن استخدامه لتنفيذ جميع توجيهات generate الموجودة في الملفات المصدرية. يمكنه أخذ اسم ملف أو اسم حزمة كمعامل إدخال للإشارة إلى الملفات التي سيتم تنفيذ توجيهات generate فيها، فيما يلي معاملاته الأخرى.
-run=regex، تشغيل توجيه generate المحدد-skip=regex، تخطي توجيه generate المحدد-n، طباعة الأوامر التي سيتم تنفيذها-x، طباعة الأوامر المنفذة أثناء العملية-v، إخراج الملفات المُعالجة
بالإضافة إلى ذلك، الأوامر المنفذة في توجيه generate تدعم أيضاً المعاملات المدمجة التالية
$GOARCH، بنية cpu$GOOS، نظام التشغيل$GOFILE، اسم الملف$GOLINE، رقم السطر$GOPACKAGE، اسم الحزمة$GOROOT، go root$DOLLAR، علامة الدولار$PATH، متغير بيئة path
انظر مثالاً، لا يوجد كود فقط سطر تعليق واحد
package main
//go:generate echo "hello world!"تنفيذ الأمر
$ go generate .
hello world!هذا المثال هو تنفيذ أمر go
package main
//go:generate go versionتنفيذ الأمر
$ go generate .
go version go1.21.3 windows/amd64توجيه generate يمكن استخدامه لتنفيذ أي أمر، مثل swagger لتوليد وثائق API، أو Wire لتوليد كود IOC. لكن هذا التوجيه غير مناسب لتنفيذ أوامر معقدة جداً، مناسب لتنفيذ أوامر قصيرة، إذا كانت هناك احتياجات معقدة يمكن استخدام نصوص برمجية أو makefile كبديل.
embed
توجيه embed أُضيف في 1.16، وظيفته هي يمكنه حزم الملفات الثابتة معاً في الملف الثنائي، مثل قوالب HTML. تنسيقه كالتالي
//go:embed patternpattern يمكن أن يكون تعبيراً نمطياً glob، أو مجلداً أو ملفاً محدداً. انظر مثالاً
package main
import "embed"
//go:embed *
var static embed.FSتوجيه embed يتطلب أن يكون فوق متغير عام من نوع embed.Fs، انتبه يجب أن يكون متغيراً عاماً، ويجب استيراد حزمة embed لاستخدامه، في هذا المثال، * يعني أن جميع الملفات في المجلد الحالي سيتم حزمها في الملف الثنائي، لكنه لن يسمح بوجود مجلدات تبدأ بـ ..
المثال التالي يوضح قراءة المحتوى من الملفات المدمجة
package main
import (
"embed"
"fmt"
)
//go:embed *.txt
var static embed.FS
func main() {
bytes, err := static.ReadFile("hello.txt")
if err != nil {
panic(err)
}
fmt.Println(string(bytes))
}له ثلاث طرق فقط، استخدامه مشابه جداً لنظام الملفات المعتاد، وبما أنه يُنفذ واجهة io/Fs، يمكن أيضاً تمريره ككائن Fs.
func (f FS) Open(name string) (fs.File, error)
func (f FS) ReadFile(name string) ([]byte, error)
func (f FS) ReadDir(name string) ([]fs.DirEntry, error)المثال التالي يوضح تضمين ملف html من خلال توجيه embed، والوصول إليه من خلال خدمة http.
package main
import (
"embed"
"net/http"
)
//go:embed index.html
var htmlFs embed.FS
func main() {
http.Handle("/", http.FileServer(http.FS(htmlFs)))
http.ListenAndServe(":8080", http.DefaultServeMux)
}نتيجة الوصول كالتالي
$ curl -s -GET 127.0.0.1:8080
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>hello world!</title>
</head>
<body>
<H1>Hello World!</H1>
<script>
alert("hello world!");
</script>
</body>
</html>توجيه embed يدعم أيضاً أن يكون نوع المتغير العام []byte، مثل المثال التالي
package main
import (
_ "embed"
"net/http"
)
//go:embed index.html
var rawdata []byte
func main() {
http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
writer.Write(rawdata)
})
http.ListenAndServe(":8080", http.DefaultServeMux)
}التأثير الذي يُحققه مشابه جداً للمثال السابق.
$ curl -s -GET 127.0.0.1:8080
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>hello world!</title>
</head>
<body>
<H1>Hello World!</H1>
<script>
alert("hello world!");
</script>
</body>
</html>build
في قسم build-التحكم في التجميع، تحدثنا عن استخدام توجيه // +build للتحكم في سلوك التجميع. وتوجيه //go:build أُضيف في 1.17، والهدف هو استبدال التوجيه السابق، لكن الآن في 1.21 لم يتم الاستبدال بعد، ويُقدر أنهما سيتواجدان معاً في المستقبل، حول هذا التوجيه الجديد، الوثائق الرسمية لديها أيضاً مقدمة: build constraints. وظيفته نفس السابق، لكن صياغته أكثر صرامة، ويدعم التعبيرات المنطقية، انظر مثالاً
//go:build (linux && 386) || (darwin && !cgo)
package pkg_nameهذه الطريقة أكثر قابلية للقراءة من الطريقة القديمة.
line
توجيه line سيؤثر على رقم السطر التالي له، ورقم العمود، واسم الملف، وظيفته تقتصر على هذا، معظم الأوقات قد يُستخدم لتصحيح الأخطاء. مثل عند حدوث خطأ، سيغير المعلومات التي يُخرجها المجمع.
package main
var a undefinedType
func main() {
}في الحالة الطبيعية، سيُخرج المجمع
.\main.go:3:7: undefined: undefinedTypeلكن إذا استُخدم توجيه line، فسيكون مختلفاً
package main
//line abc.go:10:100
var a undefinedType
func main() {
}فسيكون إخراجه
abc.go:10:106: undefined: undefinedTypeوبسبب الأسباب التاريخية، توجيه line هو أيضاً التوجيه الوحيد الذي يختلف استخدامه عن التوجيهات الأخرى. تنسيقه هو
//line filename:line:columnيمكنك أن ترى أنه لا يحتاج إلى go: كبادئة.
linkname
هذا التوجيه يمكن استخدامه لربط دوال أو متغيرات عامة من حزم أخرى، حتى لو كانت أنواعاً خاصة، هذه العملية تحدث كثيراً في المكتبة القياسية وخاصة runtime، هناك بعض الدوال ليس لها جسم دالة يتم تنفيذها بهذه الطريقة، والجزء الآخر من الدوال التي لها جسم دالة فارغ يتم تنفيذها بالتجميع. لنرَ استخدامه، تنسيق الاستخدام كالتالي
//go:linkname اسم نوع الربط النوع المرتبطوقبل الاستخدام، يجب استيراد حزمة unsafe. انظر مثالاً بسيطاً لربط نوع خاص في المكتبة القياسية
import (
"fmt"
"unsafe"
)
//go:linkname memhash runtime.memhash
func memhash(p unsafe.Pointer, h, s uintptr) uintptr
func MemHash(data []byte) uint64 {
ptr := unsafe.Pointer(unsafe.SliceData(data))
return uint64(memhash(ptr, 0, uintptr(len(data))))
}
func main() {
fmt.Println(MemHash([]byte("hello")))
}الإخراج
15395306441938000233يربط الدالة الخاصة runtime.memhash بالدالة التي أعلنا عنها بأنفسنا، هذه الدالة ليس لها جسم دالة فقط توقيع، وتلعب دور حامل فقط. وظيفة memhash هي إعطاء مؤشر، وبذرة تجزئة، وإزاحة ذاكرة، وحساب قيمة التجزئة بناءً على الذاكرة. عملية الربط هذه تتم أثناء التجميع،
إذا لم تكن مكتبة قياسية، فالوضع مختلف قليلاً، مثل وجود دالة test في حزمة example، قبل الربط يجب أولاً استيراد هذه الحزمة بشكل مجهول.
package example
// نوع خاص، لا يمكن الوصول إليه من الخارج.
func test() string {
return "a"
}package main
import (
"fmt"
_ "golearn/example"
_ "unsafe"
)
//go:linkname test golearn/example.test
func test() string
func main() {
fmt.Println(test())
}الإخراج
aيمكنك أن ترى أن الربط قد نجح، هذه الطريقة يمكنها تجاوز نظام وحدات go والقيام بما تريد، لكن لا يُنصح باستخدامها على نطاق واسع، إلا إذا كنت تعرف ما تفعله.
noinline
توجيه noinline يشير إلى أن دالة ممنوعة من تحسين الدمج، حتى لو كانت بسيطة جداً. انظر مثالاً بسيطاً
package main
func val() string {
return "val"
}
func main() {
var c = val()
_ = c
}val دالة بسيطة جداً، وظيفتها هي إرجاع حرفي سلسلة، وبسبب بساطتها الشديدة وأن نتيجتها يمكن التنبؤ بها دائماً، فأثناء التجميع سيتم تحسينها إلى الشكل التالي
package main
func main() {
var c = "val"
_ = c
}لنرَ شكلها المُجمّع، يمكننا أن نرى أنه لم يتم العثور على استدعاء دالة val.
TEXT main.val(SB), NOSPLIT|NOFRAME|ABIInternal, $0-0
FUNCDATA $0, gclocals·g2BeySu+wFnoycgXfElmcg==(SB)
FUNCDATA $1, gclocals·g2BeySu+wFnoycgXfElmcg==(SB)
LEAQ go:string."val"(SB), AX
MOVL $3, BX
FUNCDATA $0, gclocals·g2BeySu+wFnoycgXfElmcg==(SB)
RETالآن لنضف توجيه noinline
package main
//go:noinline
func val() string {
return "val"
}
func main() {
var c = val()
_ = c
}لنرَ شكلها المُجمّع مرة أخرى
CMPQ SP, 16(R14)
PCDATA $0, $-2
JLS 17
PCDATA $0, $-1
PUSHQ BP
MOVQ SP, BP
FUNCDATA $0, gclocals·g2BeySu+wFnoycgXfElmcg==(SB)
FUNCDATA $1, gclocals·g2BeySu+wFnoycgXfElmcg==(SB)
PCDATA $1, $0
CALL main.val(SB)
POPQ BP
RETهذه المرة يمكننا أن نرى بوضوح استدعاء main.val، وهذا بالضبط ما يفعله توجيه noinline، منع المجمع من دمج الدوال أثناء التحسين.
nospilit
توجيه nospilit وظيفته هي تخطي فحص تجاوز المكدس. بما أن نموذج الجدولة المتزامنة في go هو جدولة استباقية، إذا كانت دالة ستشغل كوداً منخفض المستوى جداً، فلا يُناسب أن تُستبعد goroutines الأخرى عند استدعاء هذه الدالة، يمكن استخدام هذا التوجيه للإشارة إلى ذلك.
//go:nosplit
func nospilitFn()بعد استخدام هذا التوجيه، لن يتم إجراء زيادة المكدس.
noescape
noescape، من اسمه يمكنك بسهولة تخمين أنه له علاقة بالهروب، وظيفته هي الإشارة إلى أن الدالة الحالية لن تحدث فيها سلوكيات هروب للذاكرة، وبعد انتهاء التنفيذ سيتم استعادة جميع الموارد، ويجب أن يكون لهذه الدالة فقط توقيع وليس جسم دالة، في هذه الحالة عموماً يتم تنفيذ الدالة بالتجميع.
مثل memhash المستخدم سابقاً سيستخدم هذا التوجيه
//go:noescape
//go:linkname memhash runtime.memhash
func memhash(p unsafe.Pointer, h, s uintptr) uintptrبهذه الطريقة، لن يقوم المجمع بإجراء تحليل الهروب عليها، بشرط أن تضمن أنها لن تحدث هروباً، إذا حدث، فلا يُعرف ما ستكون العواقب.
uintptrescapes
توجيه uintptrescapes يشير إلى أن معاملات النوع uinptr في هذه الدالة تم تحويلها إلى قيم مؤشر وهربت إلى الكومة، ويجب أن تبقى حية. هذا التوجيه يُستخدم عموماً لبعض استدعاءات النظام منخفضة المستوى، معظم الحالات لا تحتاج لمعرفته.
//go:uintptrescapes
func nospilit(ptr uintptr) uintptrفي السابق كان يجب أن يكون هناك توجيه notinheaps للإشارة إلى أن نوعاً ما لا يُسمح له بتخصيص الذاكرة على الكومة، لا أعرف في أي إصدار تم حذفه.
norace
توجيه norace يشير إلى أن وصول الذاكرة لدالة ما لم يعد يحتاج لتحليل التسابق، عادةً ما يُستخدم عند تشغيل كود منخفض المستوى غير مناسب لتحليل التسابق.
//go:norace
func low_level_code(ptr uintptr) uintptrTIP
هناك أيضاً بعض التوجيهات التي تُقيد استخدامها على حزمة runtime فقط، لا يمكن استخدامها من الخارج، تتعلق بأشياء أعمق، لمعرفة المزيد يمكنك الانتقال إلى Runtime-only compiler directives للاطلاع على مقدمة عنها.
