Go
Programowanie obiektowe
Szukaj…
Uwagi
Interfejsu nie można zaimplementować w odbiornikach wskaźnikowych, ponieważ *User
nie jest User
Struktury
Go obsługuje typy zdefiniowane przez użytkownika w postaci struktur i aliasów typów. Struktury są typami złożonymi, a elementy składowe danych, które tworzą typ struktury, nazywane są polami . pole ma typ i nazwę, które muszą być niepotrzebne.
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]}
}
jest to również legalna składnia do definiowania struktur
type User struct {
ID uint64
FullName, Email string
}
user := new(User)
user.ID = 1
user.FullName = "Zelalem Mekonen"
user.Email = "[email protected]"
Wbudowane struktury
ponieważ struct jest również typem danych, może być używany jako pole anonimowe, zewnętrzna struktura może bezpośrednio uzyskiwać dostęp do pól wbudowanej struktury, nawet jeśli struktura pochodzi z innego pakietu. to zachowanie zapewnia sposób na wyprowadzenie części lub całości implementacji z innego typu lub zestawu typów.
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
}
Metody
W Go metodą jest
funkcja, która działa na zmienną określonego typu, zwaną odbiornikiem
odbiornikiem może być wszystko, nie tylko structs
ale nawet function
, typy aliasów dla typów wbudowanych, takich jak int
, string
, bool
mogą mieć metodę, wyjątkiem od tej reguły jest to, że interfaces
(omówione później) nie mogą mieć metod, ponieważ Interfejs jest abstrakcyjną definicją, a metoda jest implementacją, próbując wygenerować błąd kompilacji.
łącząc structs
i methods
, można uzyskać ścisły odpowiednik class
w programowaniu obiektowym.
metoda w Go ma następujący podpis
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
}
Wskaźnik Vs Odbiornik wartości
odbiornik metody jest zwykle wskaźnikiem ze względu na wydajność, ponieważ nie wykonalibyśmy kopii instancji, tak jak w przypadku odbiornika wartości, jest to szczególnie prawdziwe, jeśli typem odbiornika jest struct. innym powodem, dla którego odbiornik powinien być wskaźnikiem, jest to, że możemy zmodyfikować dane, na które wskazuje odbiornik.
odbiornik wartości służy do uniknięcia modyfikacji danych, które zawiera odbiornik, odbiornik vaule może spowodować obniżenie wydajności, jeśli odbiornik jest dużą strukturą.
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]
}
Interfejs i polimorfizm
Interfejsy zapewniają sposób określania zachowania obiektu, jeśli coś może to zrobić, można go tutaj użyć. interfejs definiuje zestaw metod, ale metody te nie zawierają kodu, ponieważ są abstrakcyjne lub implementacja jest pozostawiona użytkownikowi interfejsu. w przeciwieństwie do większości języków zorientowanych obiektowo interfejsy mogą zawierać zmienne w Go.
Polimorfizm jest istotą programowania obiektowego: zdolność do równego traktowania obiektów różnych typów, o ile przylegają do tego samego interfejsu. Interfejsy Go zapewniają tę funkcję w bardzo bezpośredni i intuicyjny sposób
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)
}