کتابخانه های استاندارد در Go (بخش اول)

Standard libraries in GOاهمیت کتابخانه های استاندارد در Go کتابخانه های استاندارد Go مجموعه ای از بسته های مرکزی هستند که زبان را گسترش داده و بهبود می بخشند. این بسته ها به برنامه نویسان این امکان را می دهند که در توسعه نرم افزار خود نگران حل مسائل دیگری غیر از هدف برنامه خود نباشند. از آنجا که این بسته ها جزئی از زبان هستند برخی ویژگی ها در موردشان تضمین شده است:برای هر نسخه از زبان وجود خواهند داشتهمیشه با نسخه های پیشین سازگار خواهند بودتوسط توسعه دهندگان اصلی زبان نگهداری و بازبینی می شوندبا هر نسخه از زبان مورد تست و ارزیابی قرار گرفته انداین ویژگی ها باعث می شوند که کتابخانه های استاندارد زبان به بخش ویژه ای از آن تبدیل شده و شما را به استفاده بدون دردسر از آنها ترغیب کنند.دسته بندی کتابخانه های استانداردکتابخانه های استاندارد Go شامل تعداد زیادی بسته هستند و پوشش کامل آنها در قالب یک پست امکان پذیر نخواهد بود. در حال حاضر بیش از 100 بسته که در 38 دسته مرتب شده اند، در زبان وجود دارند.archive, debug, hash ,mime, sort, time, bufio, encoding, html, net, strconv, unicode, bytes, errors, image, os, strings, unsafe, compress, expvar, index, path, sync, container, flag, io, reflect, syscall, crypto, fmt, log, regexp, testing, database, go, math, runtime, textبرخی از دسته های ذکر شده در بالا خود، بسته های زبان هستند. برای توضیحات دقیق و جزئی تر می توانید مستندات زبان را بررسی کنید. این مستندات در قالب godoc تهیه شده و هر بسته را به تفکیک انواع و متدها تشریح می کنند. به عنوان نمونه Int از بسته rand (از زیر مجموعه های بسته math) به صورت زیر تشریح شده است:func Int func Int() int Int returns a non-negative pseudo-random int from the default Source.صرف نظر از نحوه نصب Go تمام کد کتابخانه های استاندارد در پوشه $GOROOT /src/pkg قابل دسترسی خواهند بود. در ادامه به معرفی چند بسته کاربردی و برخی از توابع آنها می پردازیم. در بخش دوم این پست نیز به بررسی کاربردی بسته io خواهیم پرداخت.بسته stringsبسته strings توابع ساده ای را برای دستکاری رشته های UTF-8 پیاده سازی کرده است. برای مطالعه دقیق تر در مورد رشته های UTF-8 در Go این پست را بخوانید. در ادامه به معرفی و کاربرد برخی از توابع این بسته می پردازیم.تابع Compareاین تابع با امضای Compare(a, b string) int به مقایسه دو رشته به صورت الفبایی پرداخته و مقدار 0 را در صورت a == b، مقدار 1 را در صورت a > b و مقدار -1 را در صورت a < b برمی گرداند. این تابع برای ایجاد تشابه با بسته bytes پیاده سازی شده است و استفاده از اپراتورهای ==، < و > بسیار سریع تر از این تابع هستند.تابع Containsاین تابع با امضای Contains(s, substr string) bool بررسی می کند که آیا substr در s وجود دارد و مقداری بولین برمی گرداند.تابع Indexاین تابع با امضای Index(s, substr string) int ایندکس مربوط به اولین رخداد substr در s را برمی گرداند.تابع Joinاین تابع با امضای Join(elems []string, sep string) string مقادیر موجود در آرگومان اول را با جداساز (آرگومان دوم) به هم چسبانده و یک رشته واحد برمی گرداند.تابع Replaceاین تابع با امضای Replace(s, old, new string, n int) string مقدار old موجود در s را با مقدار new جایگزین کرده و رشته جدید را بر می گرداند. مقدار n تعداد تکرار این عملیات را مشخص می کند. اگر n کوچکتر از 0 باشد این عملیات برای همه رخدادها تکرار می شود.تابع Split این تابع با امضای Split(s, sep string) []string، یک رشته و یک جداساز را دریافت کرده و رشته را بر اساس وقوع جداساز به یک لیست از رشته ها تبدیل کرده و مقدار لیست را برمی گرداند.بسته strconvاین بسته تبدیل انواع داده ها به رشته و برعکس را پیاده سازی کرده است. در ادامه به معرفی برخی از توابع این بسته می پردازیم.توابع Atoi و Ltoaتبدیل یک رشته به مقدار صحیح و برعکس توسط این توابع انجام می گردد.i, err := strconv.Atoi(&quot-42&quot) s := strconv.Itoa(-42)توابع دسته Parseاین توابع تبدیل از رشته به مقادیر بولین، اعداد صحیح یا اعشاری را بر عهده دارند.b, err := strconv.ParseBool(&quottrue&quot) f, err := strconv.ParseFloat(&quot3.1415&quot, 64) i, err := strconv.ParseInt(&quot-42&quot, 10, 64) u, err := strconv.ParseUint(&quot42&quot, 10, 64)توابع دسته Formatاین توابع تبدیل از مقادیر بولین، اعداد صحیح یا اعشاری به رشته را بر عهده دارند.s := strconv.FormatBool(true) s := strconv.FormatFloat(3.1415, 'E', -1, 64) s := strconv.FormatInt(-42, 16) s := strconv.FormatUint(42, 16)بسته mathاین بسته تابث ها و توابع ریاضی را در خود جای داده است. (مشکل اعداد اعشاری در زبان های برنامه نویسی در این بسته نیز پابرجا است.) در ادامه به معرفی برخی ثابت ها و توابع این بسته می پردازیم.ثابت های ریاضیconst ( E = 2.71828182845904523536028747135266249775724709369995957496696763 // https://oeis.org/A001113 Pi = 3.14159265358979323846264338327950288419716939937510582097494459 // https://oeis.org/A000796 Phi = 1.61803398874989484820458683436563811772030917980576286213544862 // https://oeis.org/A001622 Sqrt2 = 1.41421356237309504880168872420969807856967187537694807317667974 // https://oeis.org/A002193 SqrtE = 1.64872127070012814684865078781416357165377610071014801157507931 // https://oeis.org/A019774 SqrtPi = 1.77245385090551602729816748334114518279754945612238712821380779 // https://oeis.org/A002161 SqrtPhi = 1.27201964951406896425242246173749149171560804184009624861664038 // https://oeis.org/A139339 Ln2 = 0.693147180559945309417232121458176568075500134360255254120680009 // https://oeis.org/A002162 Log2E = 1 / Ln2 Ln10 = 2.30258509299404568401799145468436420760110148862877297603332790 // https://oeis.org/A002392 Log10E = 1 / Ln10 )تابع Absاین تابع با امضای Abs(x float64) float64 قدرمطلق مقدار x را برمی گرداند.تابع Ceil این تابع با امضای Ceil(x float64) float64 نزدیک ترین عدد صحیح بزرگتر از مقدار x را برمی گرداند. تابع Floorاین تابع با امضای Floor(x float64) float64 نزدیک ترین عدد صحیح کوچکتر از مقدار x را برمی گرداند. تابع Infاین تابع با امضای Inf(sign int) float64 مقدار مثبت یا منفی بی نهایت را با توجه به مقدار sign برمی گرداند.تابع Maxاین تابع با امضای Max(x, y float64) float64 ماکزیمم دو عدد x و y را برمی گرداند.تابع Minاین تابع با امضای Min(x, y float64) float64 مینیمم دو عدد x و y را برمی گرداند.تابع Powاین تابع با امضای Pow(x, y float64) float64 عدد x را به توان y رسانده و حاصل را برمی گرداند.تابع Sqrt این تابع با امضای Sqrt(x float64) float64 جذر عدد x را برمی گرداند.بسته errorsاین بسته برای مدیریت خطاها پیاده سازی شده است. تابع New برای ساخت یک خطای جدید مورد استفاده قرار می گیرد و تنها یک رشته را به عنوان ورودی می پذیرد.‍‍‍package main import ( &quoterrors&quot &quotfmt&quot ) func main() { err := errors.New(&quotemit macho dwarf: elf header corrupted&quot) if err != nil { fmt.Print(err) } }بسته fmtاین بسته برای توابع ورودی و خروجی فرمت شده را پیاده سازی کرده است. عملکرد توابع این بسته مشابه printf و scanf از زبان C است. کلمات فرمت با الهام از زبان C ولی ساده تر از آن گسترش داده شده اند. برخی از کلمات چاپ عبارت اند از:%v مقدار در فرمت پیشفرض %#v مقدار در فرمت زبان %T نوع مقدار %t مقدار صحیح %b عدد در مبنای دو %d عدد در مبنای ده %o عدد در مبنای هشت %f عدد اعشاری %s مقدار رشته %p آدرس مقداردر ادامه به بررسی برخی از توابع این بسته می پردازیم.تابع Fscanfاین تابع با امضای Fscanf(r io.Reader, format string, a ...interface{}) (n int, err error) رشته ورودی را اسکن کرده و مقادیر تعیین شده در رشته فرمت شده را در مقادیر جای می دهد. r := strings.NewReader(&quot5 true gophers&quot) n, err := fmt.Fscanf(r, &quot%d %t %s&quot, &i, &b, &s) if err != nil { fmt.Fprintf(os.Stderr, &quotFscanf: %v\n&quot, err) } fmt.Println(i, b, s) fmt.Println(n)تابع Sprintfاین تابع با امضای Sprintf(format string, a ...interface{}) string یک رشته فرمت شده به همراه متغیرهای ورودی را دریافت کرده و با جایگزین کردن مقدار متغیرها در رشته، رشته حاصل را بر می گرداند.s := fmt.Sprintf(&quot%s is %d years old.\n&quot, &quotMehrdad&quot, 22)بسته timeاین بسته تسهیلاتی برای اندازه گیری و نمایش زمان را پیاده سازی کرد است. محاسبات بر اساس تاریخ میلادی هستند. برخی ثابت های بسته عبارت اند از:UnixDate = &quotMon Jan _2 15:04:05 MST 2006&quot RubyDate = &quotMon Jan 02 15:04:05 -0700 2006&quot RFC822 = &quot02 Jan 06 15:04 MST&quot RFC822Z = &quot02 Jan 06 15:04 -0700&quot // RFC822 with numeric zone RFC850 = &quotMonday, 02-Jan-06 15:04:05 MST&quot RFC1123 = &quotMon, 02 Jan 2006 15:04:05 MST&quot RFC3339 = &quot2006-01-02T15:04:05Z07:00&quot RFC3339Nano = &quot2006-01-02T15:04:05.999999999Z07:00&quot Kitchen = &quot3:04PM&quot Nanosecond Duration = 1 Microsecond = 1000 * Nanosecond Millisecond = 1000 * Microsecond Second = 1000 * Millisecond Minute = 60 * Second Hour = 60 * Minuteدر ادامه به معرفی برخی توابع این بسته می پردازیم.تابع Sleep این تابع با امضای Sleep(d Duration) اجرای goroutine فعلی را به اندازه d نگه داشته و سپس به کار خود ادامه می دهد. d باید مقداری از ثابت های بسته time باشد.time.Sleep(100 * time.Millisecond)تابع ParseDurationاین تابع با امضای ParseDuration(s string) (Duration, error) رشته ای را دریافت کرده و معادل آن را در قالب بسته time برمی گرداند.hours, _ := time.ParseDuration(&quot10h&quot) micro, _ := time.ParseDuration(&quot1µs&quot)تابع Dateاین تابع با امضای Date(year int, month Month, day, hour, min, sec, nsec int, loc *Location) Time مقادیر سال، ماه، روز و ... را دریافت کرده و زمان متناظر با آن را برمی گرداند. t := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)تابع Nowاین تابع با امضای Now() Time زمان محلی کنونی را برمی گرداند.تابع Parseاین تابع با امضای Parse(layout, value string) (Time, error) یک رشته فرمت شده را به زمان تجزیه کرده و نتیجه را برمی گرداند.const longForm = &quotJan 2, 2006 at 3:04pm (MST)&quot t, _ := time.Parse(longForm, &quotFeb 3, 2013 at 7:54pm (PST)&quot)تابع Unixاین تابع با امضای Unix(sec int64, nsec int64) Time زمان محلی کنونی را در فرمت یونیکس برمی گرداند.بسته jsonاین بسته انکد و دیکد کردن JSON طبق تعریف RFC 7159 را پیاده سازی کرده است. در ادامه دو تابع پرکاربرد این بسته که برای دیکد و انکد کردن JSON مورد استفاده قرار می گیرند را معرفی می کنیم.تابع Marshalاین تابع با امضای Marshal(v interface{}) ([]byte, error) ورودی را به لیستی از بایت ها در فرمت JSON تبدیل می کند.func main() { type ColorGroup struct { ID int Name string Colors []string } group := ColorGroup{ ID: 1, Name: &quotReds&quot, Colors: []string{&quotCrimson&quot, &quotRed&quot, &quotRuby&quot, &quotMaroon&quot}, } b, err := json.Marshal(group) if err != nil { fmt.Println(&quoterror:&quot, err) } os.Stdout.Write(b) }تابع Unmarshalاین تابع با امضای Unmarshal(data []byte, v interface{}) error عکس عمل Marshal را یعنی تبدیل لیستی از بایت های در قالب JSON به متغیری از جنس زبان Go را انجام می دهد. func main() { var jsonBlob = []byte(`[ {&quotName&quot: &quotPlatypus&quot, &quotOrder&quot: &quotMonotremata&quot}, {&quotName&quot: &quotQuoll&quot, &quotOrder&quot: &quotDasyuromorphia&quot} ]`) type Animal struct { Name string Order string } var animals []Animal err := json.Unmarshal(jsonBlob, &animals) if err != nil { fmt.Println(&quoterror:&quot, err) } fmt.Printf(&quot%+v&quot, animals) }بسته sha512این بسته الگوریتم های درهم سازی SHA-384, SHA-512, SHA-512/224, و SHA-512/256 را که در FIPS 180-4 تعریف شده اند را پیاده سازی کرده است. ثابت های تعریف شده در این بسته اندازه checksum خروجی در بایت هستند. Size = 64 Size224 = 28 Size256 = 32 Size384 = 48 BlockSize = 128در ادامه به معرفی برخی توابع این بسته می پردازیم.تابع Newاین تابع با امضای New() hash.Hash مقدار SHA-512 checksum جدیدی را برمی گرداند.تابع Sum512این تابع با امضای Sum512(data []byte) [Size]byte مقدار SHA512 checksum مقدار data را برمی گرداند.بسته zlibاین بسته امکان خواندن و نوشتن در فرمت zlib که در RFC 1950 تعریف شده است را پیاده سازی کرده است. در ادامه دو تابع که برای خواندن و نوشتن مورد استفاده قرار می گیرند را معرفی می کنیم.تابع NewReaderاین تابع با امضای NewReader(r io.Reader) (io.ReadCloser, error) مقداری را از r خوانده و از حالت فشرده خارج می کند. buff := []byte{120, 156, 202, 72, 205, 201, 201, 215, 81, 40, 207, 47, 202, 73, 225, 2, 4, 0, 0, 255, 255, 33, 231, 4, 147} b := bytes.NewReader(buff) r, err := zlib.NewReader(b) if err != nil { panic(err) } io.Copy(os.Stdout, r) r.Close()تابع NewWriter این تابع با امضای NewWriter(w io.Writer) *Writer نویسنده ای برای فشرده سازی بافر مهیا می کند. بستن این نویسنده به عهده فراخواننده آن خواهد بود. var b bytes.Buffer w := zlib.NewWriter(&b) w.Write([]byte(&quothello, world\n&quot)) w.Close() fmt.Println(b.Bytes())نتیجه گیریتوابع و ثابت های بسیار زیادی در قالب کتابخانه های استاندارد Go پیاده سازی شده اند. مرور و مطالعه این کتابخانه ها به شما این امکان را می دهد که با نحوه پیاده سازی و ساختار زبان آشنا شده و چرخ های موجود را دوباره اختراع نکنید (!). استفاده از کتابخانه های استاندارد علاوه بر خوانا کردن کد به شما امکان پشتیبانی از نسخه های پیشین را نیز می دهند.