برنامه نویسی

همه چیز در مورد Generics Go

پوشش

ژنریک چیست

برنامه نویسی عمومی یک سبک یا الگوی زبانهای برنامه نویسی است. Generics به برنامه نویسان اجازه می دهد تا با استفاده از برخی از انواع که بعداً مشخص شده اند ، کد را در زبان های برنامه نویسی به شدت تایپ بنویسند و این نوع به عنوان پارامترها در حین لحظه ارائه می شود.

Generics شما را قادر می سازد تا کدی را بنویسید که می تواند در چندین نوع استفاده شود بدون اینکه همان منطق را برای هر نوع تکرار کنید. این قابلیت استفاده مجدد از کد ، انعطاف پذیری و ایمنی را بهبود می بخشد.

در GO ، ژنرال ها از طریق پارامترهای نوع اجرا می شوند. یک پارامتر نوع یک نوع خاص از پارامتر است که به عنوان یک مکان نگهدارنده استفاده می شود که می تواند هر نوع باشد. آنها در تعاریف توابع ، روش ها و انواع استفاده می شوند و در طی تماس های بتونی با انواع خاصی جایگزین می شوند.

قبل از ژنرال

این نیاز را در نظر بگیرید: عملکردی را اجرا کنید که دو مورد طول بکشد int پارامترها و کوچکتر این دو را برمی گرداند. این یک نیاز بسیار ساده است و ما به راحتی می توانیم کد زیر را بنویسیم:

func Min(a, b int) int {
    if a < b {
        return a
    }
    return b
}
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

این عالی به نظر می رسد ، اما عملکرد محدودیت دارد: پارامترها فقط می توانند از نوع باشند intبشر اگر نیاز گسترش یابد و ما باید از مقایسه دو پشتیبانی کنیم float64 مقادیر و بازگشت کوچکتر ، ممکن است بنویسیم:

func Min(a, b int) int {
    if a < b {
        return a
    }
    return b
}
func MinFloat64(a, b float64) float64 {
    if a < b {
        return a
    }
    return b
}
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

ممکن است توجه داشته باشید که به محض گسترش نیاز ، ما باید تغییراتی را نیز انجام دهیم ، دائماً کارهای تکراری انجام می دهیم. ژنرال ها دقیقاً همان چیزی هستند که این مشکل را حل می کنند.

import "golang.org/x/exp/constraints"

func Min[T constraints.Ordered](x, y T) T {
    if x < y {
        return x
    }
    return y
}
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

نحو اساسی ژنرال ها

// Function definition
func F[T any](p T){...}
// Type definition
type M[T any] []T

// Constraint represents specific type constraints, such as any, comparable
func F[T Constraint](p T){..}

// The “~” symbol is used to represent underlying type constraints
type E interface {
   ~string
}

// Specify several types
type UnionElem interface {
   int | int8 | int32 | int64
}
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

نماد ~

در Go Generics ، ~ از نماد برای نشان دادن محدودیت نوع اساسی استفاده می شود.

به عنوان مثال ، ~int به معنای پذیرش هر نوع است که نوع اصلی آن است int، از جمله انواع سفارشی اگر یک نوع سفارشی وجود دارد MyInt نوع اساسی آنهاست int، سپس این محدودیت می تواند قبول کند MyInt نوع.

type MyInt int

type Ints[T int | int32] []T

func main() {
   a := Ints[int]{1, 2}     // Correct
   b := Ints[MyInt]{1, 2}   // Compilation error
   println(a)
   println(b)
}
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

MyInt does not satisfy int | int32 (possibly missing ~ for int in int | int32)compilerInvalidTypeArg

فقط آن را به شرح زیر تغییر دهید:

type Ints[T ~int | ~int32] []T
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

محدودیت های نوع

  • any: هر نوع را می پذیرد
  • comparable: پشتیبانی می کند == وت != عمل
  • ordered: از اپراتورهای مقایسه مانند پشتیبانی می کند >با <

برای انواع دیگر ، به آدرس زیر مراجعه کنید: https://pkg.go.dev/golang.org/x/exp/constints

چه موقع از ژنریک استفاده کنیم

چه موقع از ژنریک استفاده کنیم

  • برای عملیات در مورد انواع ظروف تعریف شده به زبان: هنگام نوشتن توابعی که بر روی انواع ظروف خاص تعریف شده توسط زبان کار می کنند ، مانند برش ها ، نقشه ها و کانال ها ، و کد عملکرد فرضیات خاصی را در مورد نوع عنصر ایجاد نمی کند ، با استفاده از پارامترهای نوع ممکن است مفید باشد. به عنوان مثال ، تابعی که قطعه ای از کلیدها را از هر نوع نقشه برمی گرداند.
  • ساختار داده های هدف کلی: برای ساختار داده های با هدف کلی مانند لیست های مرتبط یا درختان باینری ، با استفاده از پارامترهای نوع می تواند ساختار داده های عمومی تری تولید کند ، یا داده ها را با کارآمدتر ذخیره کند ، از ادعاهای نوع خودداری کنید و در زمان ساخت ، بررسی کامل را انجام دهید.
  • اجرای روشهای عمومی: هنگامی که انواع مختلف نیاز به پیاده سازی برخی از روش های متداول دارند ، و این پیاده سازی ها دقیقاً یکسان به نظر می رسند ، با استفاده از پارامترهای نوع ممکن است مفید باشد. به عنوان مثال ، یک نوع عمومی اجرا sort.Interface برای هر نوع برش
  • توابع را بیش از روش ها ترجیح دهید: هنگامی که به چیزی مانند عملکرد مقایسه نیاز دارید ، استفاده از توابع به جای روش ها را ترجیح دهید. برای انواع داده های هدف کلی ، ترجیح داده می شود از توابع به جای نوشتن محدودیت هایی که به روش نیاز دارند استفاده شود.
// SliceFn implements sort.Interface for a slice of T.
type SliceFn[T any] struct {
    s    []T
    less func(T, T) bool
}

func (s SliceFn[T]) Len() int {
    return len(s.s)
}
func (s SliceFn[T]) Swap(i, j int) {
    s.s[i], s.s[j] = s.s[j], s.s[i]
}
func (s SliceFn[T]) Less(i, j int) bool {
    return s.less(s.s[i], s.s[j])
}
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

// SortFn sorts s in place using a comparison function.
func SortFn[T any](s []T, less func(T, T) bool) {
    sort.Sort(SliceFn[T]{s, less})
}
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

در صورت عدم استفاده از ژنریک

  • انواع رابط را جایگزین نکنید: اگر فقط نیاز به فراخوانی روش ها بر روی یک نوع خاص دارید ، باید از انواع رابط به جای پارامترهای نوع استفاده کنید. به عنوان مثال ، شما نباید تابعی را تغییر دهید که از انواع رابط استفاده می کند تا از پارامترهای نوع استفاده کند.
  • از پارامترهای نوع استفاده نکنید که در هنگام اجرای روش ها متفاوت است: اگر اجرای روش برای هر نوع متفاوت است ، باید از انواع رابط استفاده کنید و به جای استفاده از پارامترهای نوع ، پیاده سازی روش های مختلف را بنویسید.
  • از بازتاب مناسب استفاده کنید: اگر برخی از عملیات باید از انواع مختلفی که حتی روش ندارند پشتیبانی کنند و عملیات برای هر نوع متفاوت است ، پس از بازتاب استفاده کنید. به عنوان مثال ، encoding/json بسته از بازتاب استفاده می کند.

راهنمای ساده

اگر خود را می بینید که دقیقاً همان کد را چندین بار می نویسید ، تنها تفاوت آن انواع مورد استفاده است ، می توانید با استفاده از پارامترهای نوع در نظر بگیرید. به عبارت دیگر ، شما باید از استفاده از پارامترهای نوع خودداری کنید تا زمانی که متوجه شوید که می خواهید چندین بار دقیقاً همان کد را بنویسید.

بی اهمیت

چرا از براکت های مربع استفاده کنید [] به جای براکت های زاویه ای < > که در زبانهای دیگر رایج است؟

https://github.com/golang/proposal/blob/master/design/15292/2013-12-type-params.md

مانند وکتور از براکت های زاویه ای استفاده کنید. این مزیت آشنایی با برنامه نویسان C ++ و جاوا است. متأسفانه ، این بدان معنی است که F (true) را می توان به عنوان یک تماس برای عملکرد F یا مقایسه F تجزیه کرد


ما Leapcell ، انتخاب برتر شما برای میزبانی پروژه های GO هستیم.

جهش

Leapcell بستر سرور نسل بعدی برای میزبانی وب ، کارهای ASYNC و REDIS است:

پشتیبانی چند زبانی

  • با node.js ، پایتون ، برو یا زنگ زدگی توسعه دهید.

پروژه های نامحدود را به صورت رایگان مستقر کنید

  • فقط برای استفاده پرداخت کنید – بدون درخواست ، بدون هزینه.

راندمان هزینه بی نظیر

  • پرداخت به عنوان شما بدون هیچ گونه هزینه بیکار.
  • مثال: 25 دلار از درخواست های 6.94M در زمان پاسخ متوسط ​​60ms پشتیبانی می کند.

تجربه توسعه دهنده ساده

  • UI بصری برای راه اندازی بی دردسر.
  • خطوط لوله CI/CD کاملاً خودکار و ادغام GITOPS.
  • معیارهای زمان واقعی و ورود به سیستم برای بینش های عملی.

مقیاس پذیری بی دردسر و عملکرد بالا

  • مقیاس خودکار برای رسیدگی به همزمانی بالا با سهولت.
  • صفر سربار عملیاتی – فقط روی ساختمان تمرکز کنید.

در اسناد بیشتر کاوش کنید!

Leapcell را امتحان کنید

ما را در X دنبال کنید: LeapCellHQ


در وبلاگ ما بخوانید

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا