编程笔记 Golang基础 009 标识符和关键字
- 一、标识符
- 二、标识符分类
- (一)空白标识符(又称下划线 `_`)
- (二)预声明标识符
- (三)唯一标识符
- (四)导出标识符
- 三、关键字
- 小结
标识符在编程语言中,包括Go语言,是一个用于命名各种程序实体的名称。这些实体可能包括变量、常量、函数、类型、包、结构体、接口等。简单来说,标识符就是程序员为程序中的各个组成部分所起的名字。
关键字在编程语言中是具有特殊含义的预定义标识符,它们不能用作变量名、函数名或其他用户自定义的标识符。关键字是由编程语言设计者保留的,用于实现特定语义或结构的关键字词组。
一、标识符
标识符在编程语言中,包括Go语言,是一个用于命名各种程序实体的名称。这些实体可能包括变量、常量、函数、类型、包、结构体、接口等。简单来说,标识符就是程序员为程序中的各个组成部分所起的名字。
在Go语言中,标识符的命名规范如下:
- 组成:标识符由字母(Unicode字母,可以包含非ASCII字符)、数字和下划线(_)组成。
- 首字符要求:标识符必须以一个字母或下划线开头,不能以数字开头。
- 大小写敏感:Go是大小写敏感的语言,因此
myVariable
与MyVariable
是两个不同的标识符。 - 保留字限制:标识符不能使用Go语言的保留关键字作为名称。
- 空标识符:下划线
_
也是一个有效的标识符,它通常用作占位符或者用于忽略函数返回值,但不应作为常规标识符使用。 - 驼峰命名法:Go语言推荐使用驼峰命名法(Camel Case),对于普通的局部变量和函数名,一般采用小驼峰式(lowerCamelCase),即首个单词首字母小写,后续每个单词首字母大写;而对于公开的(导出的)包成员(如变量、常量、类型、函数和方法),则建议使用大驼峰式(UpperCamelCase),即所有单词首字母均大写。
示例:
// 正确的标识符命名
var myVariable int
func myFunction() {}
type user struct{}
const maxItems uint = 100// 公开(导出)的标识符应以大写字母开头
package somePackage
var PublicVar int
func PublicFunc() {}
type PublicType struct{}
此外,Go语言还强调代码的可读性和一致性,鼓励开发者使用有意义且描述性强的标识符名称来提高代码的可维护性。
二、标识符分类
(一)空白标识符(又称下划线 _
)
Go语言中的空白标识符(又称下划线 _
)是一个特殊的标识符,它具有多种用途和特性:
-
忽略值:
- 在函数返回多值时,如果不需要某个返回值,可以使用空白标识符来接收并丢弃这个值。
func multipleReturns() (int, error) {// ...return 42, nil }_, err := multipleReturns() // 这里只关心错误信息,因此用_来忽略第一个返回值
- 在函数返回多值时,如果不需要某个返回值,可以使用空白标识符来接收并丢弃这个值。
-
导入包而不使用其导出成员:
- 当你仅需要导入一个包以触发它的初始化代码执行(比如注册http处理程序),但并不直接使用该包的任何导出项时,可以使用空白标识符导入该包。
import _ "net/http/pprof"
- 当你仅需要导入一个包以触发它的初始化代码执行(比如注册http处理程序),但并不直接使用该包的任何导出项时,可以使用空白标识符导入该包。
-
循环中忽略元素:
- 在
for range
循环中,如果你只需要迭代中的一个值而不需要另一个值,可以将不关注的值赋给空白标识符。for _, c := range "hello" {fmt.Println(c) } // 这里仅打印字符串中的每个字符,不关心字符的索引位置
- 在
-
类型断言:
- 空白标识符可用于类型断言以检查接口类型的实现,但并不存储实际的值。
var reader io.Reader var _ io.Writer = reader // 如果reader不是io.Writer类型,这里会编译失败
- 空白标识符可用于类型断言以检查接口类型的实现,但并不存储实际的值。
-
匿名占位符:
- 空白标识符由于没有名称,常被看作是匿名占位符,用于在语法上满足某些需求,但实际上并不引用或存储任何数据。
总之,Go语言中的空白标识符是一种灵活的工具,主要用于在编程中表示对某个值或功能的有意忽视,或者用于特定的语义场景。
(二)预声明标识符
在Go语言中,预声明标识符是指那些在编译器内部已经定义和初始化的标识符,它们可以直接在任何包内使用,无需进行导入或其他显式声明。这些预声明标识符包括:
-
布尔型常量:
true
和false
-
空值:
nil
,它代表了接口、指针、映射、切片和通道类型的零值。
-
内置类型名称:
- 基本数字类型:
int
,int8
,int16
,int32
,int64
,uint
,uint8
(别名byte
),uint16
,uint32
,uint64
,uintptr
- 浮点数类型:
float32
,float64
- 复数类型:
complex64
,complex128
- 字符串类型:
string
- 编程原语:
rune
(用于表示单个Unicode码点,等同于int32
) - 时间相关类型:
time.Duration
- 基本数字类型:
-
内置函数:
- 数组、切片和映射操作:
append
,copy
,delete
,len
,cap
- 类型断言与转换:
new
,make
,typeAssert
- 数据类型判断与转换:
panic
,recover
,iota
,interface{}
(空接口) - 格式化与打印:
print
,println
,fmt.Printf
等一系列来自fmt
包的全局函数 - 内存分配与处理:
unsafe.Sizeof
,unsafe.Alignof
,unsafe.Offsetof
,unsafe.Pointer
- 数组、切片和映射操作:
-
特殊常量:
iota
是一个特殊的常量生成器,用在常量声明时自增计数。
需要注意的是,尽管有些预声明的标识符是函数或者具有类似函数的行为,但它们并非传统意义上的关键字,因为它们是可以被重新声明或赋值的。然而,这通常不推荐这样做,以免混淆代码逻辑并违反最佳实践。预声明标识符主要是为了提供方便的基础功能,使得开发者可以快速且高效地编写Go程序。
(三)唯一标识符
在Go语言中,标识符(identifiers)用于命名程序的各个组成部分,如变量、常量、函数、类型等。标识符的唯一性是基于其作用域和名称来实现的:
-
名称唯一性:
在同一作用域内,每个标识符必须具有唯一的名称。这意味着在同一文件、函数或块内部,你不能重复声明同名的变量、函数或其他标识符。例如,在同一个包里,你不能有两个同名的函数或类型。// 错误示例:在同一作用域内不能有相同名称的函数 func myFunction() {// ... }func myFunction() { // 编译错误:重复定义// ... }
-
大小写敏感:
Go语言是大小写敏感的,因此MyVar
与myvar
被认为是两个不同的标识符。 -
导出规则与唯一性:
对于公开(exported)标识符,即首字母大写的标识符,它们在整个包外部也是唯一的。也就是说,不同包内的两个公开标识符可以有相同的名称,但当它们被导入到另一个包时,通过包名进行限定以确保唯一性。package pkgAtype MyType struct{}// 在另一个包pkgB中 package pkgBimport ("pkgA" )// 这里使用了完全限定的名字来引用pkgA中的MyType var a pkgA.MyType
-
作用域内的唯一性:
即使两个不同的包内存在相同名称的非公开标识符,只要它们在各自的作用域内不冲突,也不会产生问题,因为它们无法相互访问。 -
嵌套作用域:
在嵌套的作用域中,内部作用域可以重用外层作用域已使用的标识符,但这仅限于内部作用域,并不会影响外层作用域中该标识符的原有含义。
综上所述,在Go语言中,标识符的唯一性是由其名称、作用域以及大小写敏感性共同保证的。在合适的范围内,标识符必须保持唯一,而跨越不同范围时,可以通过包名等机制区分。
(四)导出标识符
在Go语言中,导出标识符是指那些可以被其他包访问的变量、常量、类型、函数和方法。Go语言通过标识符的首字母大小写来控制其可见性:
-
导出规则:
- 如果一个标识符(包括但不限于变量名、函数名、类型名等)的第一个字符是大写字母(Unicode类别“Lu”),那么这个标识符就是导出(exported)的。
- 如果一个标识符的第一个字符是小写字母或下划线,则它不是导出的,只能在定义它的同一个包内使用。
-
示例:
package mypackage// 导出的变量 var ExportedVar = "This is exported"// 非导出的变量 var unexportedVar = "This is not exported"// 导出的函数 func ExportedFunc() {// ... }// 非导出的函数 func unexportedFunc() {// ... }// 导出的类型 type ExportedType struct {Field string }// 导出的方法 func (e ExportedType) ExportedMethod() {}// 非导出的方法 func (e ExportedType) unexportedMethod() {}
-
外部包访问:
其他包想要访问mypackage
中的导出标识符时,需要通过导入声明,并使用包名加上标识符的方式来引用:package mainimport ("mypackage" )func main() {// 访问导出的变量fmt.Println(mypackage.ExportedVar)// 调用导出的函数mypackage.ExportedFunc()// 创建并使用导出的类型e := mypackage.ExportedType{Field: "Value"}e.ExportedMethod() }
总结来说,在Go语言中,如果你想让某个标识符能够被其他包所看见和使用,那么必须确保该标识符以大写字母开头。这是Go语言实现封装和模块化设计的重要手段之一。
三、关键字
关键字在编程语言中是具有特殊含义的预定义标识符,它们不能用作变量名、函数名或其他用户自定义的标识符。关键字是由编程语言设计者保留的,用于实现特定语义或结构的关键字词组。
Go语言中的关键字如下:
break
:用于退出循环(如for或switch)。default
:在switch语句中表示默认分支。func
:用于声明函数和方法。interface
:用于定义接口类型。select
:用于并发编程中的通信控制,与channel操作相关联,类似于一个基于channel的多路复用选择器。case
:在switch或select语句中定义条件分支。chan
:用于创建通道类型,支持Go的并发特性。defer
:用于延迟执行函数调用,直到包含它的函数返回时才执行。struct
:定义结构体类型。goto
:跳转到标签(label)处。package
:定义代码包。switch
:用于条件多路选择。const
:声明常量。fallthrough
:在switch语句中使用,使得匹配的case之后不再检查其他条件,直接执行下一个case的语句块。map
:声明映射类型。if
和else
:用于条件判断。range
:用于迭代数组、切片、字符串、映射以及channel中的元素。type
:声明新类型或别名类型。continue
:在循环中跳过当前迭代的剩余部分,进入下一轮迭代。for
:通用循环语句,可以配合初始化、条件和后置表达式使用。import
:导入其他包。return
:从函数或方法返回值。var
:声明变量。go
:启动一个新的并发goroutine来执行函数。goto
:虽然存在,但在Go语言中不推荐使用,用于无条件跳转到同文件内的标记位置。
这些关键字对于理解和编写Go程序至关重要,它们构建了Go语言的语法基础,并且赋予了语言独特的特性和功能。
小结
标识符和关键字是构成编程语言的基础。后面将逐渐展开。