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

我的解读:

3. 固定类型

在 Go 里面,如果没有明确指定常量的数据类型,那么这个常量就是 untyped 的,untypedtyped 的区别可以用这段代码来说明:

[[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
}

常见的默认类型为:

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()

6. Ref