قدم های کودک با Go – انجمن DEV

تصمیم گرفتم Go را در سفرم امتحان کنم تا زبان جدیدی را انتخاب کنم که برای حرفه و علایقم مفید باشد. این بار من در حال رفتن به Go. من فکر می کنم با توجه به برداشت های اولیه، بسیار خوب است.
این یک تور با راهنما نیست، و بهعنوان یادآوری شخصی، برای هیچ کس دیگری غیر از خودم نوشته نشده است.
من یک پروژه کوچک برای آن به خودم دادم به نام Os-Release-Q. قصد من این بود که بتوانم روی هر سیستمی که مدیریت میکنم، یک باینری داشته باشم، به طوری که بتوانم دقیقاً اطلاعات مورد نیاز خود را چاپ کنم، بدون اینکه نیازی به تجزیه و تحلیل یا بررسی آنها داشته باشم.
مانع اول: import
جستجو در وب در مورد وارد کردن بستههای دیگران بسیار صحبت میکند، اما در مورد سازماندهی کدهای خود بسیار کم است. حتی اسناد روی آن تمرکز می کنند go get
به جای تفکیک نگرانی ها
من در هر زبانی با این مانع مواجه میشوم، زیرا هر کدام فلسفه خاص خود را در مورد چگونگی انجام آن و محدودیتهایی که هر کدام دارند یا تحمیل میکنند، دارند.
از بین تمام فعالیتهایی که در یادگیری اصول اولیه انجام دادم، از یک پسزمینه عمدتاً پایتون، تقسیم کدم به چندین فایل، بیشترین زمان را برای دریافت پاسخها از من گرفت. به طور خلاصه موارد زیر را پیدا کردم:
- نیازهای سطح بالا a
go.mod
اعلام می کندmodule module-name
- سپس می توانم a را تنظیم کنم
src/
دایرکتوری در سطح بالا، و الفsrc/main.go
که در آن تابع اصلی خود را با a قرار دهمpackage main
اعلامیه در بالا - قرار دادن کد در فایل های دیگر به سادگی ایجاد یک فایل مشابه است
src/others.go
با یکpackage main
اعلام. - همه توابع و متغیرها مستقیماً در هر فایل دیگری از موجود می شوند
package main
، اما فایل ها باید به صراحت در مورد ذکر شوندgo build FILES
زنگ زدن
برای زیر ماژول های محلی، زیرماژول باید در یک پوشه قرار گیرد. می تواند الف را اعلام کند package submodule-name
.
بگو داخل است src/submod/
، با مجری اصلی در src/submod/submod.go
. که در main.go
ما انجام می دهیم import "module-name/src/submod"
(با module-name
کشیده شده از go.mod
). و بعد میتونیم زنگ بزنیم submod.SomeFunction()
.
توجه داشته باشیم که توابع زیر ماژول تنها در صورتی در دسترس واردکنندگان هستند که نام آنها با یک حرف بزرگ شروع شود. پس هیچ کاری submod.myFunction()
– باید اینطور باشد submod.MyFunction()
.
مطمئناً ملاحظات دیگری در مورد ماژولهای فرعی و واردات وجود دارد، اما تا آنجا که سازماندهی و تفکیک کدها را نگه دارید، این موارد ضروری است.
برای عاقل نگه داشتن همه چیز، وسوسه شدم که فقط یک فایل اعلام کننده داشته باشم package main
، و جداسازی بقیه در زیر ماژول ها – اینها به طور خودکار بدون نیاز به اعلام در ماژول ها وارد می شوند go build FILES
لیست فایل ها
انجام کارهای اساسی
بعد از اینکه این ویژگی Go را حل کردم، بقیه به راحتی در جای خود قرار گرفتند. برای هر کار اساسی البته یک ورودی StackOverflow یا یک صفحه GoByExample.com و اساساً مرجع زبان Go وجود داشت.
- دست زدن به رشته از طریق انجام می شود
strings
بسته بندی - مدیریت آرایه دارای تعدادی توابع بومی است که یکی از آنها
base_array = append(base_array, item1, item2)
الگو – همچنین برای گسترش یک آرایه با مقادیر آرایه دیگر از طریق کار می کندappend(base, other_array...)
- مدیریت خطا معمولاً با حذف اشیاء خطا انجام می شود، اما نه لزوما.
- آ
"log"
lib برای یک گزارش از پیش پیکربندی شده مفید وجود دارد. شامل الف استlog.Fatal(message)
تماس بگیرید که یک خطا ثبت می کند، و همچنین بلافاصله خارج می شود. - فراخوانی فرآیندهای فرعی از طریق
"os/exec"
کتابخانه، با استفاده ازexec.Command(base, args...)
الگو
دو کار به خصوص رایج سزاوار پاراگراف های خاص خود هستند.
رسیدگی به خطا
مدیریت خطای اساسی اغلب به عنوان دست و پا گیر توصیف می شود، به معنای واقعی کلمه نیاز به رسیدگی به خطاها در میان جریان کنترل دارد. این ممکن است برای برنامه نویسان که از یک گردش کاری امتحان/گرفتن می آیند، ناخوشایند باشد، اما رسیدگی به این موضوع در نقطه ای که ممکن است اتفاق بیفتد چندان بد نیست.
// explicit return item `err` forces us to be aware of it
// but having the ability to check it in the same breath is not so bad
if result, err := someCall(); err != nil {
log.Fatal("Sorry.")
}
// Equally valid is
/*
result, err := someCall()
if err != nil {
log.Fatal("Sorry")
}
*/
fmt.Println(result)
روش تلاش/گرفتن را مقایسه کنید
try:
result = someCall()
print(result)
except:
print("Sorry") # a little divorced from potential origin of error
sys.exit(1)
تجزیه استدلال
من نمی توانم کمک کنم اما احساس می کنم که اجرای flags
کتابخانه کمی نیمه کاره است بدیهی است که با توجه به بقای آن در شکل کنونی، مردم به آن عادت دارند و با آن موافق هستند.
صدا زدن program -flag arg1 arg2
این ضامن را به ما می دهد flag
تنظیم شده است، و positionals := flags.Args()
آرایه را به ما برمی گرداند ["arg1", "arg2"]
با این حال تماس program arg1 arg2 -flag
میکند نه هر چیزی را تغییر دهید -flags
قرار است انجام دهد، و در عوض می دهد است positionals
مانند ["arg1", "arg2", "-flag"]
که در آن پرچم تجزیه نشد.
این ممکن است برای ارسال در یک تماس فرعی مانند مفید باشد program colorize ls -l
جایی که ls -l
به معنای واقعی کلمه منتقل می شود – بنابراین من می توانم یک مورد استفاده را ببینم.
فقط بیشتر برنامههای موجود در آنجا اجازه میدهند که آرگومانهای پرچم در هر جایی در اطراف آیتمهای موقعیتی باشند. ls dir1/ -l dir2/
مثل این هست که ls -l dir1/ dir2/
، و این قراردادی است که بر روی اکثریت قریب به اتفاق دستورات یونیکس و لینوکس وجود دارد.
ممکن است این چیزی باشد که باید به آن عادت کرد – و ارزش تماس گرفتن را دارد.
مورد هدف و کاربرد Go
از پارادایم وارد کردن فایل که بگذریم، پیادهسازی برنامه پایهام بسیار آسان است. هر کاری که من اشتباه می کردم کاملاً واضح بود و اشتباهات معنی دار بودند. واقعاً احساس می کنم که می توانم فقط روی “انجام کارها” تمرکز کنم.
از میزان استفاده بسیار ناچیز من تا کنون، و با در نظر گرفتن نیازهای خاص خود، می توانم متوجه شوم
- آسان برای شروع
- باینری کامپایل شده، بدون وابستگی زمان اجرا
- زبان ساده با انواع یک گام بالاتر از برنامه نویسی پوسته است
- ظاهراً پشتیبانی از چند پردازش آسان
من فکر می کردم داشتن انواع کم به جای اشیاء و ارث مانعی است، اما تا اینجا خوب است. من بدون آنها در زبان های دیگر کار می کنم، بنابراین فکر می کنم وقتی به تعریف واسط ها و انواع می پردازم، احساس می کنم یک پله بالاتر از Lua و bash است. امیدوارم.
یکی از دلایلی که میخواستم یک زبان کامپایلشده به بومی را کشف کنم، این بود که بتوانم باینریهایی تولید کنم که به راحتی قابل جابجایی باشند، بدون نیاز به تکیه بر نسخه خاصی از زمان اجرا.
اخیراً یکی از همکاران با ناراحتی به سمت میز من رفت و سعی کرد جاوا 17 را بر روی یک تصویر پایه Node قدیمی که مبتنی بر Debian 10 بود، حل کند. یا باید نسخه Node را ارتقا دهد تا یک تصویر پایه جدیدتر دریافت کند، از یک تصویر پایه جدید دبیان استفاده کند و Node را به صورت دستی نصب و پیکربندی کند، یا اینترنت را برای یک مخزن سفارشی که توسط goodness-knows-who for a goodness-knows میزبانی شده است جستجو کند. -اگر جاوا 17 هک شود که روی دبیان 10 اجرا می شود.
اگر نرم افزار مستقر شده چنین وابستگی های زمان اجرا متناقضی نداشته باشد، چقدر راحت تر است…
از نقطه نظر عملیات، یک دستاورد بزرگی که احساس میکنم احساس میکنم این است: میتوانم به راحتی کد بنویسم، و یک باینری ELF بسازم تا سپس بر روی “سیستم دلخواه X” مستقر شود و مجبور نباشم با اطمینان از حق مبارزه کنم. نسخهای از زمان اجرا مشخص شده است و وابستگیهای متضاد را مدیریت میکند.
من مطمئن هستم که مزایای دیگری نیز وجود دارد، و من چیزهای زیادی درباره سهولت استفاده از multithreading و multiprocessing در Go شنیده ام، و من قصد دارم یک پروژه کوچک بسازم تا آن را به عنوان مرحله بعدی بررسی کنم – احتمالا چیزی که ممکن است به ورودیها در چندین کانال گوش دهد و در پاسخ، برخی از وظایف اساسی را انجام دهد. من یک مورد استفاده برای آن در برخی از کارهای اتوماسیون آزمایشی که قبلا انجام داده ام داشته ام، بنابراین در این مرحله برای من بیگانه نیست.