Go
Programmazione orientata agli oggetti
Ricerca…
Osservazioni
L'interfaccia non può essere implementata con i ricevitori puntatore perché *User
non è User
Structs
Go supporta i tipi definiti dall'utente sotto forma di strutture e digita alias. le strutture sono tipi compositi, le parti componenti dei dati che costituiscono il tipo di struttura sono chiamate campi . un campo ha un tipo e un nome che deve essere unqiue.
package main
type User struct {
ID uint64
FullName string
Email string
}
func main() {
user := User{
1,
"Zelalem Mekonen",
"[email protected]",
}
fmt.Println(user) // {1 Zelalem Mekonen [email protected]}
}
questa è anche una sintassi legale per definire le strutture
type User struct {
ID uint64
FullName, Email string
}
user := new(User)
user.ID = 1
user.FullName = "Zelalem Mekonen"
user.Email = "[email protected]"
Strutture incorporate
poiché una struct è anche un tipo di dati, può essere usata come un campo anonimo, la struct esterna può accedere direttamente ai campi della struct incorporata anche se la struct proviene da un pacchetto diffrent. questo comportamento fornisce un modo per ricavare parte o tutta l'implementazione da un altro tipo o da un insieme di tipi.
package main
type Admin struct {
Username, Password string
}
type User struct {
ID uint64
FullName, Email string
Admin // embedded struct
}
func main() {
admin := Admin{
"zola",
"supersecretpassword",
}
user := User{
1,
"Zelalem Mekonen",
"[email protected]",
admin,
}
fmt.Println(admin) // {zola supersecretpassword}
fmt.Println(user) // {1 Zelalem Mekonen [email protected] {zola supersecretpassword}}
fmt.Println(user.Username) // zola
fmt.Println(user.Password) // supersecretpassword
}
metodi
In Go a method is
una funzione che agisce su una variabile di un certo tipo, chiamata ricevitore
il ricevitore può essere qualsiasi cosa, non solo structs
ma anche una function
, i tipi di alias per i tipi built-in come int
, string
, bool
possono avere un metodo, un'eccezione a questa regola è che le interfaces
(discusse più tardi) non possono avere metodi, poiché l'interfaccia è una definizione astratta e un metodo è un'implementazione, provando a generare un errore di compilazione.
combinando le structs
e i methods
è possibile ottenere un equivalente eqivalente di una class
nella programmazione orientata agli oggetti.
un metodo in Go ha la seguente firma
func (name receiverType) methodName(paramterList) (returnList) {}
package main
type Admin struct {
Username, Password string
}
func (admin Admin) Delete() {
fmt.Println("Admin Deleted")
}
type User struct {
ID uint64
FullName, Email string
Admin
}
func (user User) SendEmail(email string) {
fmt.Printf("Email sent to: %s\n", user.Email)
}
func main() {
admin := Admin{
"zola",
"supersecretpassword",
}
user := User{
1,
"Zelalem Mekonen",
"[email protected]",
admin,
}
user.SendEmail("Hello") // Email sent to: [email protected]
admin.Delete() // Admin Deleted
}
Pointer Vs Value receiver
il ricevitore di un metodo è di solito un puntatore per il motivo delle prestazioni perché non faremo una copia dell'istanza, come nel caso del ricevitore di valore, ciò è particolarmente vero se il tipo di destinatario è una struttura. un motivo in più per fare in modo che il ricevitore digiti un puntatore sarebbe in modo da poter modificare i dati a cui punta il ricevitore.
un ricevitore di valore viene utilizzato per evitare la modifica dei dati contenuti nel ricevitore, un ricevitore di vaule può causare un colpo di prestazioni se il ricevitore è una struttura di grandi dimensioni.
package main
type User struct {
ID uint64
FullName, Email string
}
// We do no require any special syntax to access field because receiver is a pointer
func (user *User) SendEmail(email string) {
fmt.Printf("Sent email to: %s\n", user.Email)
}
// ChangeMail will modify the users email because the receiver type is a ponter
func (user *User) ChangeEmail(email string) {
user.Email = email;
}
func main() {
user := User{
1,
"Zelalem Mekonen",
"[email protected]",
}
user.SendEmail("Hello") // Sent email to: [email protected]
user.ChangeEmail("[email protected]")
fmt.Println(user.Email) // [email protected]
}
Interfaccia e polimorfismo
Le interfacce forniscono un modo per specificare il comportamento di un oggetto, se qualcosa può farlo, allora può essere usato qui. un'interfaccia definisce un insieme di metodi, ma questi metodi non contengono codice in quanto sono astratti o l'implementazione è lasciata all'utente dell'interfaccia. a differenza della maggior parte delle interfacce linguistiche orientate agli oggetti possono contenere variabili in Go.
Il polimorfismo è l'essenza della programmazione orientata agli oggetti: la capacità di trattare oggetti di tipi diversi in modo uniforme purché aderiscano alla stessa interfaccia. Le interfacce Go forniscono questa funzionalità in modo molto diretto e intuitivo
package main
type Runner interface {
Run()
}
type Admin struct {
Username, Password string
}
func (admin Admin) Run() {
fmt.Println("Admin ==> Run()");
}
type User struct {
ID uint64
FullName, Email string
}
func (user User) Run() {
fmt.Println("User ==> Run()")
}
// RunnerExample takes any type that fullfils the Runner interface
func RunnerExample(r Runner) {
r.Run()
}
func main() {
admin := Admin{
"zola",
"supersecretpassword",
}
user := User{
1,
"Zelalem Mekonen",
"[email protected]",
}
RunnerExample(admin)
RunnerExample(user)
}