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

Standard libraries in 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 پیاده سازی شده اند. مرور و مطالعه این کتابخانه ها به شما این امکان را می دهد که با نحوه پیاده سازی و ساختار زبان آشنا شده و چرخ های موجود را دوباره اختراع نکنید (!). استفاده از کتابخانه های استاندارد علاوه بر خوانا کردن کد به شما امکان پشتیبانی از نسخه های پیشین را نیز می دهند.