همه چیز در مورد 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.
- معیارهای زمان واقعی و ورود به سیستم برای بینش های عملی.
مقیاس پذیری بی دردسر و عملکرد بالا
- مقیاس خودکار برای رسیدگی به همزمانی بالا با سهولت.
- صفر سربار عملیاتی – فقط روی ساختمان تمرکز کنید.
در اسناد بیشتر کاوش کنید!
ما را در X دنبال کنید: LeapCellHQ
در وبلاگ ما بخوانید