Στην πιο απλή της μορφή, ένας τύπος διεπαφής είναι ένα σύνολο από υπογραφές μεθόδων.
Ακολουθεί ένα παράδειγμα ορισμού διεπαφής που περιλαμβάνει δύο μεθόδους, τις 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
Αυτό σημαίνει ότι το Stats μπορεί πλέον να χρησιμοποιηθεί σε όλα τα σημεία που περιμένουν τη διεπαφή Counter.
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
}
Αντί να επαναλαμβάνει τις υπογραφές των μεθόδων Read και Close για να ορίσει το ReadCloser, ο ορισμός της διεπαφής αξιοποιεί τους υπάρχοντες ορισμούς των 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"
}