Constants
Declaration
func main() {
const myConst ...
//Not MYCONST because it will be exported (variable name rules)
}
It won't get error if you declare a const variable then not use it.
func main() {
const a = 5
const b = 6
fmt.Printf("%v %T\n", a, a)
}
//no error
Type Constant
const is like var, but const cannot be modified
func main() {
const myConst int = 42
fmt.Printf("%v %T\n", myConst, myConst)
myConst = 66 //cannot assign to myConst (constant 42 of type int)
}
If the value of constant is defined at runtime, it cannot be declared
func main() {
const myConst float64 = math.Sin(1.57) //math.Sin(1.57) (value of type float64) is not constant
const b int = test() //b() (value of type int) is not constant
fmt.Printf("%v %T\n", myConst, myConst)
}
func test() int {
return 30
}
Array (collection) is mutable, so it cannot be declared as constant
Constant can be shadowed
const a int16 = 33
const b int16 = 31
func main() {
const a int8 = 3
var b int8 = 5
fmt.Printf("%v %T\n", a, a) //3 int8
fmt.Printf("%v %T\n", b, b) //5 int8
}
There is actually no need to add a type (non-declaration) when const is declared
func main() {
const a = 3
fmt.Printf("%v %T\n", a, a) //3 int
}
What's interesting about non-declaration is that although different types of integer can't be added together, the compiler will judge by itself and change the type.
This behavior is what var does not have in non-declaration.
func main() {
const a = 3
var b int16 = 688
fmt.Printf("%v %T\n", a+b, a+b) //691 int16
}
The compiler will automatically convert type.
func main() {
const a = 42
var b int16 = 688
var c int8 = 55
fmt.Printf("%v %T\n", a+b, a+b) //730 int16
fmt.Printf("%v %T\n", a+c, a+c) //97 int8
}
counterexample
func main() {
const a int8 = 3 //Declare the type first.
var b int16 = 688
fmt.Printf("%v %T\n", a+b, a+b) //invalid operation: a + b (mismatched types int8 and int16)
}
The difference from var is that when using a block, if the next variable has no assigned value, the value assigned above will be used
const (
a = 5
b = "hello"
c
)
func main() {
fmt.Printf("%v %T\n", c, c) //hello string
}
enumerated constant
iota, which can only be used for constant, is an enumeration constant (counter), starting with 0, and will be +1 every time it is declared in the constant block
Does not overlap between different constant blocks
const a = iota
const (
b = iota
c
)
const (
d = iota
)
func main() {
fmt.Printf("%v %T\n", a, a) //0 int
fmt.Printf("%v %T\n", b, b) //0 int
fmt.Printf("%v %T\n", c, c) //1 int
fmt.Printf("%v %T\n", d, d) //0 int
}
iota can use addition, subtraction, multiplication and division to do offset
const (
a = iota + 2
b //iota + 2
c = iota - 2
d //iota - 2
)
func main() {
fmt.Printf("%v\n", a) //2
fmt.Printf("%v\n", b) //3
fmt.Printf("%v\n", c) //0
fmt.Printf("%v\n", d) //1
}
The case of using iota
Give constants to different states and check them in the program
const (
_ = iota
normal
hard
veryHard
)
func main() {
var difficulty int = normal
if difficulty == normal {
//do something in normal difficulty
}
}
Beware that iota starts from zero. If the first constant is not declared as _ (directly discarded), it usually declare as error variable.
const (
err = iota
normal
hard
veryHard
)
func main() {
var difficulty int
if difficulty == error {
fmt.Println("error because difficulty is zero-value")
//this line will print out
}
}
bit shifting with iota
const (
_ = iota
KB = 1 << (10 * iota)
MB
GB
)
func main() {
fileSize := 4000000000.
fmt.Printf("%.2fGB", fileSize/GB) //3.73GB
}
Boolean flags for Storing Permissions
const (
isAdmin = 1 << iota
isMember
isVisitor
canSeeA
canSeeB
canSeeC
)
func main() {
var role byte = isAdmin | canSeeA | canSeeB
fmt.Printf("%b\n", role) //11001
if role&isAdmin == isAdmin {
fmt.Printf("isAdmin") //will print out
}
}