Constants
Constants are declared like variables, but with the const
keyword.
Constants can be character, string, boolean, or numeric values.
Constants cannot be declared using the :=
syntax.
package main
import "fmt"
const Pi = 3.14
func main() {
const World = "世界"
fmt.Println("Hello", World)
fmt.Println("Happy", Pi, "Day")
const Truth = true
fmt.Println("Go rules?", Truth)
}
Constants in Go are just that—constant. They are created at compile time, even when defined as locals in functions, and can only be numbers, characters (runes), strings or booleans. Because of the compile-time restriction, the expressions that define them must be constant expressions, evaluatable by the compiler. For instance, 1<<3
is a constant expression, while math.Sin(math.Pi/4)
is not because the function call to math.Sin
needs to happen at run time.
In Go, enumerated constants are created using the iota
enumerator. Since iota
can be part of an expression and expressions can be implicitly repeated, it is easy to build intricate sets of values.
type ByteSize float64
const (
_ = iota // ignore first value by assigning to blank identifier
KB ByteSize = 1 << (10 * iota)
MB
GB
TB
PB
EB
ZB
YB
)
The ability to attach a method such as String
to any user-defined type makes it possible for arbitrary values to format themselves automatically for printing. Although you’ll see it most often applied to structs, this technique is also useful for scalar types such as floating-point types like ByteSize
.
func (b ByteSize) String() string {
switch {
case b >= YB:
return fmt.Sprintf("%.2fYB", b/YB)
case b >= ZB:
return fmt.Sprintf("%.2fZB", b/ZB)
case b >= EB:
return fmt.Sprintf("%.2fEB", b/EB)
case b >= PB:
return fmt.Sprintf("%.2fPB", b/PB)
case b >= TB:
return fmt.Sprintf("%.2fTB", b/TB)
case b >= GB:
return fmt.Sprintf("%.2fGB", b/GB)
case b >= MB:
return fmt.Sprintf("%.2fMB", b/MB)
case b >= KB:
return fmt.Sprintf("%.2fKB", b/KB)
}
return fmt.Sprintf("%.2fB", b)
}
The expression YB
prints as 1.00YB
, while ByteSize(1e13)
prints as 9.09TB
.
The use here of Sprintf
to implement ByteSize
’s String
method is safe (avoids recurring indefinitely) not because of a conversion but because it calls Sprintf
with %f
, which is not a string format: Sprintf
will only call the String
method when it wants a string, and %f
wants a floating-point value.
Reference
- https://tour.golang.org/basics/15
- https://blog.golang.org/constants
- https://golang.org/doc/effective_go.html#constants