1 انٹرفیس کی تعارف
1.1 انٹرفیس کیا ہے
Go زبان میں، انٹرفیس ایک قسم ہوتی ہے، ایک خلاصہ قسم۔ انٹرفیس مخصوص عمل کو صارف کو دکھاتی ہے اور مخصوص تفصیلات کو چھپاتی ہے۔ انٹرفیس میں میثاقی میں مخصوص عمل تعین کرتی ہے، مگر یہ عمل کوئی فعالیت نہیں کرتا ہے؛ بلکہ یہ مخصوص قسم کی طرف سے فراہم کیا جاتا ہے۔ Go زبان کی انٹرفیس کی خصوصیت ہے غیر دخلی ہونا، جو یہ مطلب ہے کہ ایک قسم کو وضاحت کرنے کے لئے کسی خصوصی انٹرفیس کو بیان کرنے کی ضرورت نہیں ہے؛ بلکہ صرف انٹرفیس کی ضروری میثاقی فراہم کرنی ہوتی ہے۔
// انٹرفیس کی تعریف
type Reader interface {
Read(p []byte) (n int, err error)
}
اس Reader
انٹرفیس میں، کسی بھی قسم جو Read(p []byte) (n int, err error)
عمل کو تعین کرتی ہے، کو کہا جا سکتا ہے کہ وہ Reader
انٹرفیس کو تعین کرتی ہے۔
2 انٹرفیس کی تعریف
2.1 انٹرفیس کی ترتیب سازی کا سنگ بنیاد
Go زبان میں، انٹرفیس کی تعریف مندرجہ ذیل ہوتی ہے:
type interfaceName interface {
methodName(parameterList) returnTypeList
}
-
interfaceName
: انٹرفیس کا نام Go کے نام رکھنے کی روایت کو پیروی کرتا ہے، جو کہ بڑے حرف سے شروع ہوتا ہے۔ -
methodName
: انٹرفیس کی ضرورت ہونے والے عمل کا نام۔ -
parameterList
: عمل کی پیرا میٹر کی فہرست، جس میں پیرامیٹرز کو کما کے ذریعے جدا کیا گیا ہو۔ -
returnTypeList
: عمل کی واپسی قسم کی فہرست۔
اگر ایک قسم نے انٹرفیس میں تمام عملوں کو تعین کیا ہو تو، تو یہ قسم وہ انٹرفیس کو تعین کرتی ہے۔
type Worker interface {
Work()
Rest()
مذکورہ بالا مثال میں Worker
انٹرفیس میں، کسی بھی قسم جس میں Work()
اور Rest()
عمل ہو، وہ Worker
انٹرفیس کو پورا کرتی ہے۔
3 انٹرفیس کی تنصیبی نظام
3.1 انٹرفیس تنصیب کے قواعد
Go زبان میں، ایک قسم کو صرف انٹرفیس میں تمام عمل تعین کرنا ہوتا ہے تاکہ اس کو انٹرفیس کو تعین کرتے ہوئے سمجھا جا سکے۔ یہ تنصیب زاویہ پر ہوتی ہے اور کسی دوسری زبانوں کی طرح صریح طور پر بیان نہیں کرنا ہوتا۔ انٹرفیس تنصیب کے قواعد مندرجہ ذیل ہیں:
- انٹرفیس کو تنصیب کرنے والی قسم ایک سٹرکٹ یا کسی دوسری کسٹم قسم ہو سکتی ہے۔
- ایک قسم کو اس انٹرفیس کے تمام عمل کو تنصیب کرنا ہوتا ہے تاکہ اس کو انٹرفیس کو تنصیب کرتے ہوئے سمجھا جا سکے۔
- انٹرفیس کے عملوں میں انٹرفیس کے عمل کی میثاقی برقرار رہنا چاہئے، جو کہ نام، پیرامیٹر کی فہرست، اور واپسی قیمتیں شامل ہیں۔
- ایک قسم مختلف انٹرفیس کو ایک ساتھ تنصیب کرسکتی ہے۔
3.2 مثال: انٹرفیس کی تنصیب کرنا
اب ایک مخصوص مثال کے ذریعے سے انٹرفیس کی تنصیب کی پروسیج اور عمل کو ڈرامہ کریں۔ Speaker
انٹرفیس کو دیکھیں:
type Speaker interface {
Speak() string
}
Human
قسم کو Speaker
انٹرفیس کو تنصیب کرنے کے لئے، ہمیں Human
قسم کے لئے ایک Speak
عمل کا تعین کرنا ہوگا:
type Human struct {
Name string
}
// Speak عمل کے ذریعے ہمان میں Speaker انٹرفیس کو تنصیب کرنے دیتا ہے۔
func (h Human) Speak() string {
return "Hello, my name is " + h.Name
}
func main() {
var speaker Speaker
james := Human{"James"}
speaker = james
fmt.Println(speaker.Speak()) // Output: Hello, my name is James
}
مذکورہ بالا کوڈ میں، Human
سٹرکچر Speaker
انٹرفیس کو Speak()
عمل کو تنصیب کرکے تنصیب کرتا ہے۔ ہم main
فنکشن میں دیکھ سکتے ہیں کہ Human
قسم کا متغیر james
Speaker
قسم کے متغیر Speaker
کو اس لئے تعین کیا گیا ہے کیونکہ james
Speaker
انٹرفیس کو پورا کرتا ہے۔
4 انٹرفیس استعمال کرنے کے فوائد اور استعمال کے امکانات
4.1 انٹرفیس کا استعمال کرنے کے فوائد
انٹرفیس کے استعمال کے کئی فوائد ہوتے ہیں:
- الگ تھلگاؤ: انٹرفیس ہمارے کوڈ کو مخصوص تفصیلات سے الگ رکھتی ہے جو کہ کوڈ کی لچک، اور محفوظ رکھتی ہے۔
- تبدیلی پذیری: انٹرفیس کی مدد سے ہمیں اندرونی تنصیب کو آسان بنایا جا سکتا ہے، جب تک نئی تنصیب پرانے انٹرفیس کو پورا کرتی ہو۔
- توسیع پذیری: انٹرفیس ہمیں پروگرام کی فعالیت کو توسیع دینے کی اجازت دیتی ہے بغیر کوئی موجودہ کوڈ تبدیل کیے بغیر۔
- آسانی سے ٹیسٹنگ: انٹرفیس یونٹ ٹیسٹنگ سادہ بناتی ہے۔ ہم ٹیسٹنگ کوڈ کے لئے انٹرفیس کو پورا کرنے کے لئے نقلی اشیاء کا استعمال کرسکتے ہیں۔
- پالیمورفزم: انٹرفیس پالیمورفزم کو بھی تنظیم کرتی ہے، جو مختلف شاخوں کو کئی مختلف سناریوز کے تحت مختلف طریقے سے ایک ہی پیغام دینے کی اجازت دیتا ہے۔
4.2 انٹرفیس کے اطلاقات
انٹرفیس گو زبان میں وسیع پیمانے پر استعمال ہوتے ہیں۔ یہاں کچھ عام استعمال کے انداز زکر ہیں:
-
استاندارد لائبریری میں انٹرفیس: مثلاً
io.Reader
اورio.Writer
انٹرفیس فائل کی پروسیسنگ اور نیٹ ورک پروگرامنگ کے لیے وسیع پیمانے پر استعمال ہوتے ہیں۔ -
ترتیب دینا:
sort.Interface
انٹرفیس میںLen()
،Less(i, j int) bool
، اورSwap(i, j int)
میتھڈز کی پیادگی کے ذریعے کسی بھی کسٹم سلائس کو کردار اندازی دینے کا امکان فراہم ہوتا ہے۔ -
HTTP ہینڈلرز:
http.Handler
انٹرفیس میںServeHTTP(ResponseWriter, *Request)
میتھاڈ کی پیادگی کے ذریعے کسٹم HTTP ہینڈلرز کا ایجاد ممکن بناتا ہے۔
یہاں ایک مثال ہے جو انٹرفیس کا استعمال ترتیب دینے کے لیے ہے:
package main
import (
"fmt"
"sort"
)
type AgeSlice []int
func (a AgeSlice) Len() int { return len(a) }
func (a AgeSlice) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a AgeSlice) Less(i, j int) bool { return a[i] < a[j] }
func main() {
ages := AgeSlice{45, 26, 74, 23, 46, 12, 39}
sort.Sort(ages)
fmt.Println(ages) // Output: [12 23 26 39 45 46 74]
}
اس مثال میں، sort.Interface
کے تین میتھڈز کو اندازی کر کے ہم AgeSlice
سلائس کو کرتا بنا سکتے ہیں، جو انٹرفیس کی صلاحیت کو موجودہ اقسام کے رویہ کو وسیع کرنے کا دکھاتا ہے۔
5 انٹرفیس کی انڈیاں خصوصیات
5.1 خالی انٹرفیس اور اس کے اطلاقات
گو زبان میں، خالی انٹرفیس ایک خاص نوع کی انٹرفیس ہے جس میں کوئی بھی میتھڈ نہیں ہوتا۔ لہذا، تقریباً کسی بھی قسم کی قیمت کو خالی انٹرفیس کے طور پر دیکھا جا سکتا ہے۔ خالی انٹرفیس interface{}
کے ذریعے ظاہر ہوتی ہے اور گو میں ایک انتہائی لچکدار قسم کے طور پر اہم کردار ادا کرتی ہے۔
// خالی انٹرفیس کی تعریف
var any interface{}
متحرک قسم کا ہینڈلنگ:
خالی انٹرفیس کسی بھی قسم کی قیمتوں کو رکھ سکتی ہے، جو کہ مختلف قسموں کے ساتھ کام کرنے کے لیے بہت مفید ہوتی ہے۔ مثلاً، جب آپ ایک ایسی فنکشن بناتے ہیں جو مختلف قسموں کے پیرامیٹر قبول کرتی ہے، تو خالی انٹرفیس، پیرامیٹر کی قسم کے طور پر استعمال کی جا سکتی ہے۔
func PrintAnything(v interface{}) {
fmt.Println(v)
}
func main() {
PrintAnything(123)
PrintAnything("hello")
PrintAnything(struct{ name string }{name: "Gopher"})
}
اوپر دی گئی مثال میں، فنکشن PrintAnything
خالی انٹرفیس قسم کے پیرامیٹر v
کو لے کر اسے پرنٹ کرتا ہے۔ PrintAnything
میں انٹیجر، اسٹرنگ، یا ایک سٹرکچر کو مداحل کروانا ممکن ہوتا ہے۔
5.2 انٹرفیس امبیڈنگ
انٹرفیس امبیڈنگ سے مراد ایک انٹرفیس کی تمام میتھڈز میں سے ایک اور انٹرفیس کو شامل کرنا ہے، اور شاید کچھ نئے میتھڈز شامل کرنا ہو۔ یہ انٹرفیس کی تعریف میں دوسری انٹرفیسز کو امبیڈ کر کے حاصل کیا جاتا ہے۔
type Reader interface {
Read(p []byte) (n int, err error)
}
type Writer interface {
Write(p []byte) (n int, err error)
}
// ریڈر رائٹر انٹرفیس ریڈر اور رائٹر انٹرفیس شامل کرتا ہے
type ReadWriter interface {
Reader
Writer
}
انٹرفیس کو امبیڈ کر کے ہم ایک زیادہ معدول اور ترتیبی انٹرفیس ساخت کر سکتے ہیں۔ اس مثال میں، ReadWriter
انٹرفیس Reader
اور Writer
انٹرفیس کے میتھڈز کو انضمام کرتا ہے، جس سے پڑھنے اور لکھنے کی فعالیت کا ایک ترکیبیتی مرحلہ حاصل ہوتی ہے۔
5.3 انٹرفیس قسم کی دعویٰ
قسم کی دعویٰ انٹرفیس کی قسم کی قیمتوں کو چیک اور تبدیل کرنے کا عمل ہے۔ جب ہمیں ایک انٹرفیس قسم سے ایک خاص قسم کی قیمت نکالنی ہوتی ہے، تو قسم کی دعویٰ بہت مفید ہوتی ہے۔
دعویٰ کی بنیادی سنٹیکس:
value, ok := interfaceValue.(Type)
اگر دعویٰ کامیاب ہوتی ہے، تو value
قسم کی پشتوانہ قیمت ہوگی، اور ok
ٹرُو
ہوگا؛ اگر دعویٰ ناکام ہوتی ہے، تو value
قسم کی زیرو قیمت ہوگی، اور ok
فلس
ہوگا۔
var i interface{} = "hello"
// دعویٰ
s, ok := i.(string)
if ok {
fmt.Println(s) // Output: hello
}
// غیر واقعی قسم کی دعویٰ
f, ok := i.(float64)
if !ok {
fmt.Println("دعویٰ ناکام ہوئی!") // Output: دعویٰ ناکام ہوئی!
اطلاقات کے سیناریو:
قسم کی دعویٰ عام طور پر خالی انٹرفیس interface{}
میں قیمتوں کی قسم تعین اور تبدیل کرنے کے لیے استعمال ہوتی ہے، یا مختلف انٹرفیسز کو پورا کرنے کی صورت میں استعمال ہوتی ہے، تاکہ ایک خاص انٹرفیس کو پورا کرنے والی قسم کو نکالا جا سکے۔
5.4 انٹرفیس اور بہتشکلیت
بہتشکلیت ایک اہم تصور ہے جو آبجیکٹ-منحصر پروگرامنگ میں استعمال ہوتا ہے۔ یہ ایک متفاوت قسم کی ڈیٹا کو ایک متحد شکل میں عمل کرنے کی ایجاد کرتا ہے۔ گو لینگویج میں، انٹرفیس بہتشکلیت حاصل کرنے کا کلیدی ذریعہ ہیں۔
انٹرفیس کے ذریعے بہتشکلیت کا عمل
type Shape interface {
Area() float64
}
type Rectangle struct {
Width, Height float64
}
type Circle struct {
Radius float64
}
// مستطیل انٹرفیس Shape کا عمل بناتا ہے
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
// سرکل انٹرفیس Shape کا عمل بناتا ہے
func (c Circle) Area() float64 {
return math.Pi * c.Radius * c.Radius
}
// مختلف شکلوں کا رقبہ حساب کرنا
func CalculateArea(s Shape) float64 {
return s.Area()
}
func main() {
r := Rectangle{Width: 3, Height: 4}
c := Circle{Radius: 5}
fmt.Println(CalculateArea(r)) // Output: مستطیل کا رقبہ
fmt.Println(CalculateArea(c)) // Output: سرکل کا رقبہ
}
اس مثال میں، Shape
انٹرفیس مختلف شکلوں کے لئے Area
میتھڈ کی تعریف کرتا ہے۔ دونوں Rectangle
اور Circle
مضبوط اقسام اس انٹرفیس کو پورا کرتے ہیں، یعنی یہ اقسام رقبہ نکالنے کی صلاحیت رکھتے ہیں۔ تفاعل CalculateArea
ایک Shape
انٹرفیس کا پیرامیٹر لے سکتا ہے اور کسی بھی انٹرفیس کو پورا کرنے والے شکل کا رقبہ حساب کر سکتا ہے۔
اس طرح، ہم آسانی سے نئے قسموں کو شامل کر سکتے ہیں بغیر کہ CalculateArea
تفاعل کی ترتیب کو ترتیب دینے کی ضرورت ہو۔ یہی بہتشکلیت کو کوڈ میں لانے کا انتہائی استعمال ہے۔