Conformitatea cu interfețele
Pentru ca un tip de date să corespundă unei interfețe, trebuie să implementeze toate metodele acestei interfețe. De exemplu:
package main
import "fmt"
type Stream interface{
read() string
write(string)
close()
}
func writeToStream(stream Stream, text string){
stream.write(text)
}
func closeStream(stream Stream){
stream.close()
}
// structură fișier
type File struct{
text string
}
// structură dosar
type Folder struct{}
// implementarea metodelor pentru tipul *File
func (f *File) read() string{
return f.text
}
func (f *File) write(message string){
f.text = message
fmt.Println("Scriere în fișierul cu textul", message)
}
func (f *File) close(){
fmt.Println("Fișierul a fost închis")
}
// implementarea metodelor pentru tipul *Folder
func (f *Folder) close(){
fmt.Println("Dosarul a fost închis")
}
func main() {
myFile := &File{}
myFolder := &Folder{}
writeToStream(myFile, "hello world")
closeStream(myFile)
//closeStream(myFolder) // Eroare: tipul *Folder nu implementează interfața Stream
myFolder.close() // Asta se poate
}
Aici este definită interfața Stream, care reprezintă un flux de date și definește trei metode: close, read și write. De asemenea, există două structuri, File și Folder, care reprezintă, respectiv, un fișier și un dosar. Pentru tipul *File sunt implementate toate cele trei metode ale interfeței Stream. Pentru tipul *Folder este implementată doar metoda close din interfața Stream.
Astfel, tipul *File implementează interfața Stream și corespunde acestei interfețe, în timp ce tipul *Folder nu o face. Prin urmare, acolo unde se cere un obiect de tip Stream, putem folosi un obiect de tipul *File, dar nu și de tipul *Folder.
De exemplu, în funcția closeStream(), care închide un flux, se primește un parametru de tipul Stream.
La apelarea acestei funcții, putem transmite un obiect de tip *File, care corespunde interfeței Stream:
closeStream(myFile)
Însă nu putem transmite un obiect de tipul *Folder:
closeStream(myFolder) // Eroare: tipul *Folder nu implementează interfața Stream
Totuși, putem apela metoda close pentru obiectul *Folder, dar aceasta va fi considerată o metodă proprie, care nu are nicio legătură cu interfața Stream.
Este de menționat și faptul că, în acest caz, metodele sunt implementate pentru tipul *File, adică pointerul la obiectul File, nu pentru tipul File. Acestea sunt două tipuri diferite. Prin urmare, tipul File nu corespunde interfeței Stream. De exemplu, nu putem scrie următoarele:
myFile2 := File{}
closeStream(myFile2) // ! Eroare: tipul File nu corespunde interfeței Stream
Implementarea mai multor interfețe
Un tip de date nu trebuie neapărat să implementeze doar metodele unei singure interfețe, pentru tipul de date se pot defini metode proprii sau pot implementa metode din alte interfețe. De exemplu:
package main
import "fmt"
type Reader interface{
read()
}
type Writer interface{
write(string)
}
func writeToStream(writer Writer, text string){
writer.write(text)
}
func readFromStream(reader Reader){
reader.read()
}
type File struct{
text string
}
func (f *File) read(){
fmt.Println(f.text)
}
func (f *File) write(message string){
f.text = message
fmt.Println("Scriere în fișierul cu textul", message)
}
func main() {
myFile := &File{}
writeToStream(myFile, "hello world")
readFromStream(myFile)
}
În acest caz, pentru tipul *File sunt implementate metodele ambelor interfețe, Reader și Writer. Astfel, putem utiliza obiectele de tip *File ca obiecte Reader și Writer.
Interfețe înlănțuite
Unele interfețe pot conține alte interfețe.
type Reader interface{
read()
}
type Writer interface{
write(string)
}
type ReaderWriter interface{
Reader
Writer
}
În acest caz, pentru ca un tip de date să corespundă unei astfel de interfețe, trebuie să implementeze toate interfețele înlănțuite. De exemplu:
package main
import "fmt"
type Reader interface{
read()
}
type Writer interface{
write(string)
}
type ReaderWriter interface{
Reader
Writer
}
func writeToStream(writer ReaderWriter, text string){
writer.write(text)
}
func readFromStream(reader ReaderWriter){
reader.read()
}
type File struct{
text string
}
func (f *File) read(){
fmt.Println(f.text)
}
func (f *File) write(message string){
f.text = message
fmt.Println("Scriere în fișierul cu textul", message)
}
func main() {
myFile := &File{}
writeToStream(myFile, "hello world")
readFromStream(myFile)
writeToStream(myFile, "lolly bomb")
readFromStream(myFile)
}
În acest caz, sunt definite trei interfețe. Interfața ReaderWriter conține interfețele Reader și Writer. Pentru ca structura File să corespundă interfeței ReaderWriter, aceasta trebuie să implementeze metodele read și write, adică metodele ambelor interfețe înlănțuite, ceea ce se face în acest caz.