In Go, there are two types of constants — untyped and typed. Historically, this is related to the language's desire to make type systems flexible and safe, allowing the compiler to detect errors at compile time, as well as ensuring type conversion only where it is allowed.
The problem arises when a programmer does not distinguish between these two categories and relies on the behavior of a constant without considering the type requirements in function declarations and interfaces. This can lead to errors during type conversion, unexpected compilation errors, or surprisingly "jumping" compatibility when calling functions.
The solution lies in a clear understanding:
const x int = 42), further work with this constant is limited to the specified type.Example code:
const Pi = 3.14 // untyped const Answer int64 = 42 // typed func printInt(a int) { fmt.Println(a) } func main() { printInt(Pi) // Error: Pi is not int (but can be explicitly converted) printInt(int(Pi)) // Ok printInt(Answer) // Ok, since Answer is already int64, and int64 to int is an explicit conversion }
Key features:
Can an untyped constant be assigned a floating-point value to an int variable without conversion?
No. Although an untyped constant can be substituted in an expression of a different type, attempting to assign a float constant to an int variable will result in a compilation error. An explicit conversion is required:
const Pi = 3.14 var x int = Pi // the compiler will produce an error var y int = int(Pi) // Ok
Does the type of an untyped constant transition to its type upon the first assignment operation?
No, the constant does not obtain a type until it is substituted in a context where a specific type is expected or is explicitly declared. Otherwise, it remains untyped.
Can large-sized numerical constants with an untyped type be used to initialize smaller-sized variables if the values fit?
Yes, if the absolute value fits within the range of the target type. Otherwise, the compiler will issue an overflow error.
Example:
const Big = 1 << 62 var x int32 = Big // Error: Big does not fit into int32 var y int64 = Big // Ok
In a complex financial project, developers declared a series of constants (percentages, coefficients) as untyped. One day, part of the functions started requiring float32 instead of float64. Automatic type pulling led to loss of precision in calculations, which was not immediately noticed.
Pros:
Cons:
In another part of the system, all constants are explicitly declared, and conversions are done explicitly:
const Discount float64 = 0.05
Pros:
Cons: