0. 概述
在之前的一篇文章(Golang Tips)中,我记录了很多关于 Go 比较特别的问题,其中有一个就是为什么不能将随机数和 time.Second 直接相乘,但是却可以直接将数字与 time.Second 相乘,所以我就探索了一下 Go 语言中关于常量的部分,在这篇文章中总结了一下。
1. C 语言中的类型问题
[[email protected]]# cat main.c
unsigned int u = 1e9;
long signed int i = -1;
... i + u ...
这个等式中的 i+u
的值是什么类型?是有符号的还是无符号的?这在 C 里面是引发 bug 的一个恶心存在,所以 Go 在设计之时就想彻底杜绝这个问题,因此不允许混合类型的数字一起操作。
2. Go 语言中的常量定义
But in Go, a constant is just a simple, unchanging value
我的解读:
- 简单的:常量只能是简单类型,不能是 struct 和 interface 类型的
- 不可变:常量不能被赋予新值
3. 固定类型
在 Go 里面,如果没有明确指定常量的数据类型,那么这个常量就是 untyped
的,untyped
和 typed
的区别可以用这段代码来说明:
[[email protected]]# cat main.go
const typedHello string = "Hello, 世界"
const untypeHello = "Hello, 世界"
func main() {
type MyString string
var m MyString
m = untypeHello
fmt.Println(m)
// m = typedHello // Type error
// fmt.Println(m)
}
也就是说,如果一个常量是固定类型(typed)的,那么只能赋值给类型完全一致的;但是,如果是 untyped 的,那么可以赋值给支持隐含类型转换的其他类型。
4. 常量默认类型
那既然默认的常量是 untyped 的,如果将一个 untyped 的常量赋值给变量怎么算?这里 Go 的处理就是常量有一个默认类型,如果赋值给变量的时候,变量的类型就是默认类型,例如这段代码就会出错:
[[email protected]]# cat main.go
func main() {
type MyString string
var m MyString
var str = "Hello, 世界"
m = str // Type error
}
常见的默认类型为:
- Integer constants default to int
- floating-point constants float64
- rune constants to rune (an alias for int32)
- imaginary constants to complex128
- 字符串自然就是 string
5. 思考问题
以下表达式为什么是合法的:
[[email protected]]# sqrt2 := math.Sqrt(2)
[[email protected]]# const millisecond = time.Second/1e3
[[email protected]]# bigBufferWithHeader := make([]byte, 512+1e6)
以下表达式为什么不合法
[[email protected]]# time.Second * rand.Int31()