Tipuri derivate
Tipuri denumite și aliasuri
Operatorul type permite definirea unui tip denumit pe baza altuia. De exemplu:
type mile uint
În acest caz, se definește tipul denumit mile, care se bazează pe tipul uint. Practic, mile reprezintă tipul uint și lucrul cu acesta va fi realizat la fel ca și cu tipul uint. Totuși, în același timp, acesta este un tip nou.
Putem defini variabile de acest tip și lucra cu ele ca obiecte ale tipului de bază uint:
package main
import "fmt"
type mile uint
func main() {
var distance mile = 5
fmt.Println(distance)
distance += 5
fmt.Println(distance)
}
Dar poate apărea întrebarea: de ce să definim un tip denumit dacă acesta se comportă la fel ca tipul uint? Să analizăm următoarea situație:
package main
import "fmt"
type mile uint
type kilometer uint
func distanceToEnemy(distance mile){
fmt.Println("distanta pentru inamic:")
fmt.Println(distance, "mile")
}
func main() {
var distance mile = 5
distanceToEnemy(distance)
// var distance1 uint = 5
// distanceToEnemy(distance1) // !Eroare
// var distance2 kilometer = 5
// distanceToEnemy(distance2) // ! eroare
}
Aici sunt definite două tipuri denumite: mile și kilometer, care practic reprezintă tipul uint și care sunt destinate pentru exprimarea distanței în mile și kilometri, respectiv. De asemenea, este definită funcția distanceToEnemy(), care afișează distanța până la un inamic ipotetic. Ca parametru, aceasta primește valoarea de tip mile, și nu de tip uint.
Acest lucru ne permite să reducem riscul de a transmite date incorecte. Astfel, datele transmise trebuie să fie definite explicit în program ca valoare de tip mile, și nu ca valoare de tip uint sau kilometer. Cele două tipuri denumite sunt considerate tipuri diferite, chiar dacă sunt bazate pe un tip comun (precum uint în acest caz).
De asemenea, tipurile denumite permit atribuirea unui sens suplimentar tipului. Astfel, utilizarea tipului „kilometer” sau „mile” în cod indică scopul variabilei sau parametrului și este mult mai descriptivă decât simplul tip uint.
O altă situație în care pot fi folosite tipurile denumite este scurtarea denumirii tipurilor atunci când acestea sunt prea lungi sau complexe. De exemplu, să analizăm următorul exemplu:
package main
import "fmt"
func action(n1 int, n2 int, op func(int, int) int){
result := op(n1, n2)
fmt.Println(result)
}
func add(x int, y int) int {
return x + y
}
func main() {
var myOperation func(int, int) int = add
action(10, 25, myOperation) // 35
}
Aici este definită funcția action, care primește două numere și o altă funcție de tipul func(int, int) int - adică o funcție care primește două numere și returnează un număr. În funcția main este definită variabila myOperation, care reprezintă funcția de tipul func(int, int) int, primește referința la funcția add și este transmisă apelului action(10, 25, myOperation).
Acum să definim un tip denumit pentru tipul func(int, int) int:
package main
import "fmt"
type BinaryOp func(int, int) int
func action(n1 int, n2 int, op BinaryOp){
result := op(n1, n2)
fmt.Println(result)
}
func add(x int, y int) int {
return x + y
}
func main() {
var myOperation BinaryOp = add
action(10, 35, myOperation) // 45
}
Acum tipul funcției func(int, int) int este proiectat pe tipul denumit BinaryOp, care reprezintă o operație binară asupra a două operande:
type BinaryOp func(int, int) int
Această denumire este mai scurtă decât definiția originală a tipului și, în același timp, este mai descriptivă (cel puțin pentru mine). Astfel, poate fi utilizată mai departe pentru a specifica tipul unui parametru:
func action(n1 int, n2 int, op BinaryOp){ ... }
sau al unei variabile:
var myOperation BinaryOp = add
Aliasuri
Tipurile denumite sunt similare cu aliasurile. Ele sunt, de asemenea, definite cu ajutorul operatorului type, dar în cazul aliasurilor, se aplică operația de atribuire:
type alias = existing_type
Totuși, un alias NU definește un tip nou și toate aliasurile pentru același tip sunt considerate identice. De exemplu:
package main
import "fmt"
type mile = uint
type kilometer = uint
func distanceToEnemy(distance mile){
fmt.Println("distanta pentru inamic:")
fmt.Println(distance, "mile")
}
func main() {
var distance mile = 5
distanceToEnemy(distance)
var distance1 uint = 5
distanceToEnemy(distance1) // ok
var distance2 kilometer = 5
distanceToEnemy(distance2) // ok
}
Aici pentru tipul uint sunt definite două aliasuri - mile și kilometer. Și, deși parametrul funcției distanceToEnemy este definit ca fiind de tip mile, i se poate transmite atât valoarea de tip uint, cât și valoarea aliasului său kilometer.
În mod obișnuit, aliasurile sunt folosite pentru a scurta denumirile altor tipuri sau pentru a defini un nume mai descriptiv.