সবচেয়ে সরল রূপে, একটি ইন্টারফেস টাইপ হলো কিছু মেথড সিগনেচারের একটি সেট।
Add ও Value নামের দুটি মেথড নিয়ে গঠিত একটি ইন্টারফেস ডেফিনিশনের উদাহরণ দেখুন:
type Counter interface {
Add(increment int)
Value() int
}
increment-এর মতো প্যারামিটার নামগুলো ইন্টারফেস ডেফিনিশন থেকে বাদ দেওয়া যায়, তবে এগুলো প্রায়ই পাঠযোগ্যতা বাড়ায়।
Go-তে ইন্টারফেসের নামে Interface বা I শব্দটি থাকে না।
বরং এগুলো প্রায়ই er দিয়ে শেষ হয়, যেমন Reader, Stringer।
যে টাইপই ইন্টারফেসের মেথডগুলো ডিফাইন করে, সেটি স্বয়ংক্রিয়ভাবে এবং অন্তর্নিহিতভাবেই ইন্টারফেসটি "ইমপ্লিমেন্ট" করে।
Go-তে implements নামে কোনো কিওয়ার্ড নেই।
নিচের টাইপটি আমরা উপরে যে Counter ইন্টারফেসটি দেখেছি, সেটি ইমপ্লিমেন্ট করে।
type Stats struct {
value int
// ...
}
func (s Stats) Add(v int) {
s.value += v
}
func (s Stats) Value() int {
return s.value
}
func (s Stats) SomeOtherMethod() {
// The type can have additional methods not mentioned in the interface.
}
ইন্টারফেসটি ইমপ্লিমেন্ট করার জন্য মেথডটির ভ্যালু রিসিভার না পয়েন্টার রিসিভার, তা গুরুত্বপূর্ণ নয়। (এগুলো নিয়ে নিশ্চিত না হলে মেথড কনসেপ্ট আবার দেখুন।)
ইন্টারফেস টাইপের একটি মান ওই মেথডগুলো যে ইমপ্লিমেন্ট করে, এমন যেকোনো মান ধরে রাখতে পারে। 1
এর মানে হলো, Counter ইন্টারফেসটি যে যে জায়গায় প্রত্যাশিত, সেখানে এখন Stats ব্যবহার করা যায়।
func SetUpAnalytics(counter Counter) {
// ...
}
stats := Stats{}
SetUpAnalytics(stats)
// works because Stats implements Counter
যদি সব ফাংশন প্যারামিটার ও রিটার্ন ভ্যালুকে কনক্রিট (অর্থাৎ নন-ইন্টারফেস) টাইপ ব্যবহার করতে হতো, তাহলে সেটি এগুলোর পুনর্ব্যবহারযোগ্যতাকে অনেকটা সীমিত করে ফেলত। প্যারামিটারের জন্য ইন্টারফেস টাইপ ব্যবহার করলে কেবল সেই আচরণই ডিফাইন করা হয়, যা ফাংশনের কাজটি করার জন্য প্রয়োজন। তখন ফাংশনটি ভিন্ন ভিন্ন কনক্রিট টাইপের প্যারামিটার নিয়ে ব্যবহার করা যায়, যতক্ষণ ওই কনক্রিট টাইপগুলো ইন্টারফেসটি ইমপ্লিমেন্ট করে। ইন্টারফেস টাইপ রিটার্ন ভ্যালু হিসেবে ব্যবহারের ক্ষেত্রেও একই যুক্তি প্রযোজ্য।
যেহেতু ইন্টারফেস অন্তর্নিহিতভাবে ইমপ্লিমেন্ট হয়, একটি টাইপ সহজেই একাধিক ইন্টারফেস ইমপ্লিমেন্ট করতে পারে। এর জন্য কেবল প্রয়োজনীয় সব মেথড ডিফাইন করা থাকলেই যথেষ্ট।
ইন্টারফেস ডেফিনিশনে অন্য ইন্টারফেসও অন্তর্ভুক্ত করা যায়। স্ট্যান্ডার্ড লাইব্রেরির একটি উদাহরণ দেখুন।
type ReadCloser interface {
Reader
Closer
}
// Based on these interfaces:
type Reader interface {
Read(p []byte) (n int, err error)
}
type Closer interface {
Close() error
}
ReadCloser ডিফাইন করার জন্য Read ও Close-এর মেথড সিগনেচার পুনরাবৃত্তি না করে, ইন্টারফেস ডেফিনিশনটি Reader ও Closer-এর বিদ্যমান ডেফিনিশন কাজে লাগায়।
Go-তে একটি খুবই বিশেষ ইন্টারফেস টাইপ আছে, খালি ইন্টারফেস টাইপটি, যাতে শূন্য মেথড থাকে।
খালি ইন্টারফেস এভাবে লেখা হয়: interface{}।
Go 1.18 বা তার পরের সংস্করণে any-ও ব্যবহার করা যায়।
এটি একটি অ্যালিয়াস হিসেবে ডিফাইন করা হয়েছিল।
যেহেতু খালি ইন্টারফেসে কোনো মেথড নেই, তাই প্রতিটি টাইপই এটি অন্তর্নিহিতভাবে ইমপ্লিমেন্ট করে। এটি এমন একটি ফাংশন ডিফাইন করতে সহায়ক, যা সাধারণভাবে যেকোনো মান গ্রহণ করতে পারে। সেক্ষেত্রে ফাংশনের প্যারামিটারটি খালি ইন্টারফেস টাইপ ব্যবহার করে।
যেমন:
func AnythingGoes(i interface{}) string {
if i == 0 {
return "zero"
}
if i == "" {
return "empty string"
}
return "something else"
}