W Go występują dwie odmiany stałych — niewyraźnie typowane (untyped) i wyraźnie typowane (typed). Historycznie wiąże się to z pragnieniem języka, aby systemy typów były elastyczne i bezpieczne, umożliwiając kompilatorowi wykrywanie błędów na etapie kompilacji oraz zapewniając konwersję typów tylko tam, gdzie jest to dozwolone.
Problem występuje, gdy programista nie rozróżnia tych dwóch kategorii i polega na zachowaniu stałej, nie uwzględniając wymogów dotyczących typów w deklaracjach funkcji i interfejsach. Może to prowadzić do błędów przy konwersji między typami, nieoczekiwanych błędów kompilacji lub nieoczekiwanej „skaczącej” kompatybilności podczas wywoływania funkcji.
Rozwiązanie polega na jasnym zrozumieniu:
const x int = 42) dalsza praca z tą stałą jest ograniczona do podanego typu.Przykład kodu:
const Pi = 3.14 // niewyraźnie typowana const Answer int64 = 42 // wyraźnie typowana func printInt(a int) { fmt.Println(a) } func main() { printInt(Pi) // Błąd: Pi nie jest int (ale można jawnie przekształcić) printInt(int(Pi)) // Ok printInt(Answer) // Ok, ponieważ Answer już jest int64, a int64 do int — jawne przekształcenie }
Kluczowe cechy:
Czy można przypisać niewyraźnie typowaną stałą wartości zmiennoprzecinkowej zmiennej typu int bez konwersji?
Nie. Chociaż niewyraźnie typowana stała może być podstawiana w wyrażeniu do różnych typów, próba przypisania stałej typu float do zmiennej typu int spowoduje błąd kompilacji. Wymagana jest wyraźna konwersja:
const Pi = 3.14 var x int = Pi // kompilator zgłosi błąd var y int = int(Pi) // Ok
Czy typ niewyraźnie typowanej stałej przechodzi do jej typu przy pierwszej operacji przypisania?
Nie, stała nie uzyskuje typu, dopóki nie jest podstawiona w kontekście, w którym oczekiwany jest określony typ, lub nie jest jawnie zadeklarowana. W pozostałych przypadkach pozostaje niewyraźna.
Czy można używać dużych stałych liczbowych o niewyraźnym typie do inicjowania zmiennych mniejszych rozmiarów, jeśli wartości mieszczą się?
Tak, jeśli wartość bezwzględna mieści się w zakresie docelowego typu. W przeciwnym razie kompilator zgłosi błąd przepełnienia.
Przykład:
const Big = 1 << 62 var x int32 = Big // Błąd: Big nie mieści się w int32 var y int64 = Big // Ok
W skomplikowanym projekcie finansowym programiści zadeklarowali szereg stałych (procenty, współczynniki) jako niewyraźnie typowane. Pewnego dnia część funkcji zaczęła wymagać float32 zamiast float64. Automatyczne dopasowanie typu doprowadziło do utraty precyzji w obliczeniach, co nie zostało od razu zauważone.
Zalety:
Wady:
W innej części systemu wszystkie stałe są zdefiniowane poprzez wyraźne zadeklarowanie typu, a konwersje są realizowane jawnie:
const Discount float64 = 0.05
Zalety:
Wady: