Int Make 居然不是关键字?

开发 前端
这是一个小白问题,有多少人知道 int 不是关键字?make 也不是关键字?我们知道每种语言都有关键字和保留字的,而 go 以关键字少著称,只有25个。

[[415774]]

本文转载自微信公众号「董泽润的技术笔记」,作者董泽润。转载本文请联系董泽润的技术笔记公众号。

这是一个小白问题,有多少人知道 int 不是关键字?make 也不是关键字?

我们知道每种语言都有关键字和保留字的,而 go 以关键字少著称,只有25个

  1. break        default      func         interface    select 
  2. case         defer        go           map          struct 
  3. chan         else         goto         package      switch 
  4. const        fallthrough  if           range        type 
  5. continue     for          import       return       var 

也就是说,我们常用的 make, cap, len不是关键字,就连基本数据类型 int, int64, float 也都不是。但是 C 语言中关键字可是非常多的

make 内置函数

  1. package main 
  2.  
  3. import "fmt" 
  4.  
  5. func main(){ 
  6.     make := func() string { 
  7.         return "hijacked" 
  8.     } 
  9.  
  10.     int := make()    // Completely OK, variable 'int' will be a string 
  11.     fmt.Println(int) // Prints "hijacked" 

这段代码 make 变量是一个闭包,返回一个字符串,而 int 变量类型是字符串。最后函数打印 hijacked. 显然这段代码很神经病,谁要这么写会被打死,但确是可以编译成功的

同时如果想继续用 make 创建 map, 或是用 int 声明变量就会报错。本质上 make, cap, len 都是 go 源码中的函数名,有点泛型的意思

  1. // The make built-in function allocates and initializes an object of type 
  2. // slice, map, or chan (only). Like new, the first argument is a type, not a 
  3. // value. Unlike new, make's return type is the same as the type of its 
  4. // argument, not a pointer to it. The specification of the result depends on 
  5. // the type: 
  6. // Slice: The size specifies the length. The capacity of the slice is 
  7. // equal to its length. A second integer argument may be provided to 
  8. // specify a different capacity; it must be no smaller than the 
  9. // length. For example, make([]int, 0, 10) allocates an underlying array 
  10. // of size 10 and returns a slice of length 0 and capacity 10 that is 
  11. // backed by this underlying array. 
  12. // Map: An empty map is allocated with enough space to hold the 
  13. // specified number of elements. The size may be omitted, in which case 
  14. // a small starting size is allocated. 
  15. // Channel: The channel's buffer is initialized with the specified 
  16. // buffer capacity. If zero, or the size is omitted, the channel is 
  17. // unbuffered. 
  18. func make(t Type, size ...IntegerType) Type 
  1. func len(v Type) int 
  1. func cap(v Type) int 

上面是 runtime 中对 make, len, cap 的函数定义,大家可以看注释或是看 builtin.go. make 接收三种类型参数:Map, Channel, Slice. 返回值是类型 T, 而不像 new 返回的是指针 *T

也就是说,变量名用 make, 只是在 main 函数这个词法块中普通的局部变量而己,同时遮蔽了 runtime 的 make 函数名

Predeclared identifiers

前面说的是 make, 那么对于 int 呢?其实道理也一样,这些都是 go 预定义的标识符 Predeclared identifiers

  1. Types: 
  2.  bool byte complex64 complex128 error float32 float64 
  3.  int int8 int16 int32 int64 rune string 
  4.  uint uint8 uint16 uint32 uint64 uintptr 
  5.  
  6. Constants: 
  7.  true false iota 
  8.  
  9. Zero value: 
  10.  nil 
  11.  
  12. Functions: 
  13.  append cap close complex copy delete imag len 
  14.  make new panic print println real recover 

其实这些都 document 在 builtin.go,包括常见的整数类型,true, false, iota, nil 以及常用的函数 make, new, copy 等等,这些在其它语言可能都对应着关键词 keywords 或是保留词

从编译原理的角度看,identifiers 和 keywords 关键词没有本质的区别,都是一个一个 token 而己

官方告诉我们,这些预定义的标识符在 universe block 块中都是隐式定义的,所以我们才能直接用。那么什么是 universe block 呢?

  1. Block = "{" StatementList "}" . 
  2. StatementList = { Statement ";" } . 

除了上面这种显示的语句块,还有很多隐式的语句块。大家要小心,因为很多时候 variable shadow 就是因为这个隐式的

  • The universe block encompasses all Go source text. 通用块包括 go 源码文本
  • Each package has a package block containing all Go source text for that package. 每个包都有一个块,包含该包的所有 Go 源代码
  • Each file has a file block containing all Go source text in that file. 每个文件都有一个文件块,包含该文件中的所有 Go 源码
  • Each "if", "for", and "switch" statement is considered to be in its own implicit block. 每个 if、for 和 switch 语句都被认为是在自己的隐式块中
  • Each clause in a "switch" or "select" statement acts as an implicit block. switch 或 select 语句中的每个子句都是一个隐式块

我们就犯过错误,命中了最后一条导致了变量 shadow. 那么问题来了,为什么 go 选择预定义标识符的方式,而不是直接定义成 keywords 呢?Go prefers the universal block over keywords because declarations can be added to the universal block without breaking existing programs

 

责任编辑:武晓燕 来源: 董泽润的技术笔记
相关推荐

2023-03-24 08:01:27

Go语言内存

2022-01-04 16:35:42

C++Protected关键字

2009-09-17 09:30:00

Linq LET关键字

2009-09-02 09:24:03

C# this关键字

2012-03-01 12:50:03

Java

2009-08-21 14:58:56

C# this关键字

2018-04-20 15:56:09

Pythonglobal关键字

2013-01-30 10:12:14

Pythonyield

2022-05-06 08:32:40

Pythonwith代码

2021-02-01 13:10:07

Staticc语言UNIX系统

2009-08-13 13:04:29

C# lock关键字

2022-06-29 08:05:25

Volatile关键字类型

2022-02-17 08:31:38

C语言staic关键字

2019-11-06 10:36:43

MavenoptionalJava

2009-08-13 17:44:34

C# using关键字

2009-08-06 17:52:23

C#增加that关键字

2019-12-20 15:19:41

Synchroinze线程安全

2011-06-14 13:26:27

volatile

2009-12-17 13:57:15

Ruby关键字

2009-08-21 14:47:59

C# base关键字
点赞
收藏

51CTO技术栈公众号