खोज…
टिप्पणियों
गो में इंटरफेस सिर्फ तय विधि सेट हैं। एक प्रकार से स्पष्ट रूप से एक इंटरफ़ेस को लागू करता है यदि इसकी विधि सेट इंटरफ़ेस का सुपरसेट है। आशय की कोई घोषणा नहीं है।
सरल इंटरफ़ेस
गो में, एक इंटरफ़ेस केवल तरीकों का एक सेट है। हम किसी दिए गए ऑब्जेक्ट के व्यवहार को निर्दिष्ट करने के लिए एक इंटरफ़ेस का उपयोग करते हैं।
type Painter interface {
Paint()
}
कार्यान्वयन प्रकार को यह घोषित करने की आवश्यकता नहीं है कि यह इंटरफ़ेस लागू कर रहा है। यह एक ही हस्ताक्षर के तरीकों को परिभाषित करने के लिए पर्याप्त है।
type Rembrandt struct{}
func (r Rembrandt) Paint() {
// use a lot of canvas here
}
अब हम एक इंटरफ़ेस के रूप में संरचना का उपयोग कर सकते हैं।
var p Painter
p = Rembrandt{}
प्रकारों की एक मनमानी संख्या द्वारा एक इंटरफ़ेस को संतुष्ट (या कार्यान्वित) किया जा सकता है। इसके अलावा एक प्रकार के इंटरफेस की एक मनमानी संख्या को लागू कर सकता है।
type Singer interface {
Sing()
}
type Writer interface {
Write()
}
type Human struct{}
func (h *Human) Sing() {
fmt.Println("singing")
}
func (h *Human) Write() {
fmt.Println("writing")
}
type OnlySinger struct{}
func (o *OnlySinger) Sing() {
fmt.Println("singing")
}
यहां, द Human
स्ट्रक्चर Singer
और Writer
इंटरफेस दोनों को संतुष्ट करता है, लेकिन OnlySinger
स्ट्रक्चर केवल Singer
इंटरफेस को संतुष्ट करता है।
खाली इंटरफ़ेस
एक खाली इंटरफ़ेस प्रकार है, जिसमें कोई विधियाँ नहीं हैं। हम इसे interface{}
रूप में घोषित करते हैं। इसमें कोई विधियाँ नहीं हैं, इसलिए हर type
इसे संतुष्ट करता है। इसलिए खाली इंटरफ़ेस में किसी भी प्रकार का मूल्य हो सकता है।
var a interface{}
var i int = 5
s := "Hello world"
type StructType struct {
i, j int
k string
}
// all are valid statements
a = i
a = s
a = &StructType{1, 2, "hello"}
इंटरफेस के लिए सबसे आम उपयोग मामला यह सुनिश्चित करना है कि एक चर एक या अधिक व्यवहार का समर्थन करता है। इसके विपरीत, खाली इंटरफ़ेस के लिए प्राथमिक उपयोग मामला एक चर को परिभाषित करने के लिए है जो किसी भी मूल्य को पकड़ सकता है, चाहे उसके ठोस प्रकार की परवाह किए बिना।
इन मूल्यों को उनके मूल प्रकारों के रूप में वापस लाने के लिए हमें बस करने की आवश्यकता है
i = a.(int)
s = a.(string)
m := a.(*StructType)
या
i, ok := a.(int)
s, ok := a.(string)
m, ok := a.(*StructType)
ok
इंगित करता है कि यदि interface a
दिए गए प्रकार के लिए परिवर्तनीय है। यदि ok
करना संभव नहीं है, तो यह false
होगा।
इंटरफ़ेस मान
यदि आप एक इंटरफ़ेस का एक वैरिएबल घोषित करते हैं, तो यह किसी भी मूल्य प्रकार को संग्रहीत कर सकता है जो इंटरफ़ेस द्वारा घोषित तरीकों को लागू करता है!
हम घोषणा करते हैं h
के interface Singer
, यह प्रकार का एक मूल्य संग्रहीत कर सकता है Human
या OnlySinger.
यह इस तथ्य के कारण है कि वे सभी Singer
इंटरफ़ेस द्वारा निर्दिष्ट विधियों को लागू करते हैं।
var h Singer
h = &human{}
h.Sing()
इंटरफ़ेस से अंतर्निहित प्रकार का निर्धारण
जाने में कभी-कभी यह जानना उपयोगी हो सकता है कि आपको किस अंतर्निहित प्रकार से पारित किया गया है। यह एक प्रकार के स्विच के साथ किया जा सकता है। यह मानता है कि हमारे पास दो संरचनाएँ हैं:
type Rembrandt struct{} func (r Rembrandt) Paint() {} type Picasso struct{} func (r Picasso) Paint() {}
पेंटर इंटरफ़ेस लागू करें:
type Painter interface { Paint() }
तब हम इस स्विच का उपयोग अंतर्निहित प्रकार को निर्धारित करने के लिए कर सकते हैं:
func WhichPainter(painter Painter) { switch painter.(type) { case Rembrandt: fmt.Println("The underlying type is Rembrandt") case Picasso: fmt.Println("The underlying type is Picasso") default: fmt.Println("Unknown type") } }
कंपाइल-टाइम चेक करें कि कोई टाइप इंटरफ़ेस को संतुष्ट करता है या नहीं
इंटरफेस और कार्यान्वयन (एक इंटरफ़ेस को लागू करने वाले प्रकार) "अलग" हैं। तो यह एक सही सवाल है कि यदि कोई इंटरफ़ेस लागू करता है तो संकलन-समय पर कैसे जांच की जाए।
एक तरीका यह संकलक पूछने के लिए जाँच करने के लिए है कि प्रकार T
औजार इंटरफ़ेस I
एक काम के लिए शून्य मान का उपयोग कर प्रयास के द्वारा है T
करने के लिए या सूचक T
, उचित रूप में। और हम अनावश्यक कचरा से बचने के लिए रिक्त पहचानकर्ता को सौंपने का विकल्प चुन सकते हैं:
type T struct{}
var _ I = T{} // Verify that T implements I.
var _ I = (*T)(nil) // Verify that *T implements I.
यदि T
या *T
I
लागू नहीं करता है, तो यह एक संकलन समय त्रुटि होगी।
यह प्रश्न आधिकारिक एफएक्यू में भी दिखाई देता है: मैं अपने प्रकार की गारंटी कैसे दे सकता हूं एक इंटरफ़ेस को संतुष्ट करता है?
स्विच टाइप करें
प्रकार स्विच का उपयोग उस चर को प्राप्त करने के लिए भी किया जा सकता है जो मामले के प्रकार से मेल खाता है:
func convint(v interface{}) (int,error) {
switch u := v.(type) {
case int:
return u, nil
case float64:
return int(u), nil
case string:
return strconv(u)
default:
return 0, errors.New("Unsupported type")
}
}
टाइप टाइप करें
आप टाइप अभिकथन के साथ वास्तविक डेटा प्रकार के इंटरफ़ेस तक पहुँच सकते हैं।
interfaceVariable.(DataType)
संरचना MyType
का उदाहरण जो इंटरफ़ेस Subber
लागू करता है:
package main
import (
"fmt"
)
type Subber interface {
Sub(a, b int) int
}
type MyType struct {
Msg string
}
//Implement method Sub(a,b int) int
func (m *MyType) Sub(a, b int) int {
m.Msg = "SUB!!!"
return a - b;
}
func main() {
var interfaceVar Subber = &MyType{}
fmt.Println(interfaceVar.Sub(6,5))
fmt.Println(interfaceVar.(*MyType).Msg)
}
बिना .(*MyType)
हम Msg
फ़ील्ड तक नहीं पहुँच पाएंगे। अगर हम interfaceVar.Msg
यह संकलन त्रुटि दिखाएगा:
interfaceVar.Msg undefined (type Subber has no field or method Msg)
एक गणितीय पहलू से इंटरफेस जाओ
गणित में, विशेष रूप से सेट थ्योरी में , हमारे पास चीजों का एक संग्रह होता है जिसे सेट कहा जाता है और हम उन चीजों को तत्वों के रूप में नाम देते हैं । हम इसके नाम के साथ A, B, C, ... या स्पष्ट रूप से ब्रेस अंकन पर इसके सदस्य को लगाने के साथ एक सेट दिखाते हैं: {a, b, c, d, e}। मान लीजिए कि हमारे पास एक मनमाना तत्व x और एक सेट Z है, तो महत्वपूर्ण प्रश्न यह है: "हम कैसे समझ सकते हैं कि x Z का सदस्य है या नहीं?"। गणितज्ञ इस प्रश्न का उत्तर एक अवधारणा के साथ देता है: एक सेट की विशेषता संपत्ति । एक सेट की विशेषता संपत्ति एक अभिव्यक्ति है जो पूरी तरह से सेट का वर्णन करती है। उदाहरण के लिए हमारे पास प्राकृतिक संख्याओं का समूह है जो {0, 1, 2, 3, 4, 5, ...} है। हम इस सेट का वर्णन इस अभिव्यक्ति के साथ कर सकते हैं: {a n | एक 0 = 0, एक एन = एक एन -1 +1}। अंतिम अभिव्यक्ति में 0 = 0, एक n = n-1 +1 प्राकृतिक संख्याओं के सेट की विशेषता गुण है। यदि हमारे पास यह अभिव्यक्ति है, तो हम इस सेट को पूरी तरह से बना सकते हैं । इस तरीके से सम संख्याओं के सेट का वर्णन करें। हम जानते हैं कि यह सेट इस संख्याओं द्वारा बनाया गया है: {0, 2, 4, 6, 8, 10, ...}। एक नज़र के साथ हम समझते हैं कि यह सभी संख्याएँ एक प्राकृतिक संख्या भी हैं, दूसरे शब्दों में अगर हम प्राकृतिक संख्याओं की विशिष्ट संपत्ति में कुछ अतिरिक्त शर्तें जोड़ते हैं, तो हम एक नई अभिव्यक्ति का निर्माण कर सकते हैं जो इस सेट का वर्णन करती है । तो हम इस अभिव्यक्ति के साथ वर्णन कर सकते हैं: {n | n प्राकृतिक संख्याओं का एक सदस्य है और 2 पर n का अनुस्मारक शून्य} है। अब हम एक फ़िल्टर बना सकते हैं जो एक सेट की विशेषता गुण प्राप्त करता है और हमारे सेट के तत्वों को वापस करने के लिए कुछ वांछित तत्वों को फ़िल्टर करता है। उदाहरण के लिए यदि हमारे पास एक प्राकृतिक संख्या फ़िल्टर है, तो दोनों प्राकृतिक संख्याएँ और यहाँ तक कि संख्याएँ भी इस फ़िल्टर को पास कर सकती हैं, लेकिन यदि हमारे पास एक समान फ़िल्टर है, तो कुछ तत्व जैसे 3 और 137871 फ़िल्टर को पारित नहीं कर सकते हैं।
गो में इंटरफ़ेस की परिभाषा एक विशेषता के गुण और तंत्र को परिभाषित करने की तरह है, जिसमें फ़ंक्शन का एक तर्क एक फिल्टर की तरह होता है, जो पता लगाता है कि तत्व हमारे वांछित सेट का सदस्य है या नहीं। कोड के साथ इस पहलू का वर्णन करें:
type Number interface {
IsNumber() bool // the implementation filter "meysam" from 3.14, 2 and 3
}
type NaturalNumber interface {
Number
IsNaturalNumber() bool // the implementation filter 3.14 from 2 and 3
}
type EvenNumber interface {
NaturalNumber
IsEvenNumber() bool // the implementation filter 3 from 2
}
Number
की विशिष्ट संपत्ति सभी संरचनाएं हैं जिनके पास IsNumber
मेथड है, NaturalNumber
वह सभी है जिसमें IsNumber
और IsNaturalNumber
विधियाँ हैं और अंत में EvenNumber
लिए सभी प्रकार हैं जिनमें IsNumber
, IsNaturalNumber
और IsEvenNumber
विधियाँ हैं। इंटरफ़ेस की इस व्याख्या के लिए धन्यवाद, आसानी से हम समझ सकते हैं कि चूंकि interface{}
पास कोई विशेषता गुण नहीं है, इसलिए सभी प्रकारों को स्वीकार करें (क्योंकि इसमें मूल्यों के बीच अंतर करने के लिए कोई फ़िल्टर नहीं है)।