一、标识符与关键字
go变量、常量、自定义类型、包、函数的命名方式必须遵循以下规则:
首字符可以是任意Unicode字符或下划线。
首字符之外的部分可以是Unicode字符、下划线或数字。
名字的长度无限制。
理论上名字里可以有汉字,甚至可以全是汉字,但实际中不要这么做。
1.1、Go语言关键字
break default func interface select case defer go map struct chan else goto package switch const if range type continue for import return fallthrough varGo语言一共有25个关键字
https://go.dev/ref/spec#Keywords

关键字的定义标准是什么?
在语言设计上,关键字必须满足:
不能作为变量名使用
不能作为函数名使用
不能作为包名使用
在词法分析阶段被识别为特殊 token
Go 语言刻意保持关键字数量很少(对比):
这是 Go 设计哲学:
简洁、最小化语法复杂度
1.2、常量
常量(constant)是:
在编译期间就确定值,运行时不可修改的数据。
在 Go 中,使用 const 关键字声明。
常量在编译时确定,而不是运行时。
常量必须立即初始化。
Go 的常量分为:
有类型常量
无类型常量(untyped constant)
可以自动适配不同类型
只要值不溢出即可
Go 常量只能是:
布尔
数字(整数、浮点、复数)
字符串
不能是:
slice
map
struct
array
在编译阶段:
常量不会占用运行时内存
编译器直接替换为字面量
属于“符号替换”
在工程中:
枚举优先使用 const + iota
权限系统使用位移 + iota
版本号使用字符串常量
数学常量使用无类型常量
1.3、数据类型
Go 的数据类型可以分为四大类:
基本类型(Basic Types)
复合类型(Composite Types)
引用类型(Reference Types)
接口类型(Interface Type)更严谨的官方分类是:
Basic types
Composite types
Function types
Interface typesint int8 int16 int32 int64 uint uint8 uint16 uint32 uint64 uintptr float32 float64 complex128 complex64 bool byte rune string error1.4、函数
函数是 Go 语言最核心的组成部分之一。Go 的函数设计非常简洁,但又非常强大(支持多返回值、匿名函数、闭包、函数作为参数等)。
append cap close complex copy delete imag len make new panic print println real recover二、操作符与表达式
2.1、算法术运算符
//arithmetic 算术运算
func arithmetic() {
var a float32 = 8
var b float32 = 3
var c float32 = a + b
var d float32 = a - b
var e float32 = a * b
var f float32 = a / b
fmt.Printf("a=%.3f, b=%.3f, c=%.3f, d=%.3f, e=%.3f, f=%.3f\n", a, b, c, d, e, f)
}2.2、关系运算符
//relational 关系运算符
func relational() {
var a float32 = 8
var b float32 = 3
var c float32 = 8
fmt.Printf("a==b吗 %t\n", a == b)
fmt.Printf("a!=b吗 %t\n", a != b)
fmt.Printf("a>b吗 %t\n", a > b)
fmt.Printf("a>=b吗 %t\n", a >= b)
fmt.Printf("a<c吗 %t\n", a < b)
fmt.Printf("a<=c吗 %t\n", a <= c)
}2.3、逻辑运算符
//logistic 逻辑运算符
func logistic() {
var a float32 = 8
var b float32 = 3
var c float32 = 8
fmt.Printf("a>b && b>c吗 %t\n", a > b && b > c)
fmt.Printf("a>b || b>c吗 %t\n", a > b || b > c)
fmt.Printf("a>b不成立,对吗 %t\n", !(a > b))
fmt.Printf("b>c不成立,对吗 %t\n", !(b > c))
}2.4、位运算符
//bit_op 位运算
func bit_op() {
fmt.Printf("os arch %s, int size %d\n", runtime.GOARCH, strconv.IntSize) //int是4字节还是8字节,取决于操作系统是32位还是64位
var a int32 = 260
fmt.Printf("260 %s\n", util.BinaryFormat(a))
fmt.Printf("-260 %s\n", util.BinaryFormat(-a)) //负数用补码表示。在对应正数二进制表示的基础上,按拉取反,再末位加1
fmt.Printf("260&4 %s\n", util.BinaryFormat(a&4))
fmt.Printf("260|3 %s\n", util.BinaryFormat(a|3))
fmt.Printf("260^7 %s\n", util.BinaryFormat(a^7)) //^作为二元运算符时表示异或
fmt.Printf("^-260 %s\n", util.BinaryFormat(^-a)) //^作为一元运算符时表示按位取反,符号位也跟着变
fmt.Printf("-260>>10 %s\n", util.BinaryFormat(-a>>10)) //正数高位补0,负数高位补1
fmt.Printf("-260<<3 %s\n", util.BinaryFormat(-a<<3)) //负数左移,可能变成正数
//go语言没有循环(无符号)左/右移符号 >>> <<<
}2.5、赋值运算符
//assignment 赋值运算
func assignment() {
var a, b int = 8, 3
a += b
fmt.Printf("a+=b %d\n", a)
a, b = 8, 3
a -= b
fmt.Printf("a-=b %d\n", a)
a, b = 8, 3
a *= b
fmt.Printf("a*=b %d\n", a)
a, b = 8, 3
a /= b
fmt.Printf("a/=b %d\n", a)
a, b = 8, 3
a %= b
fmt.Printf("a%%=b %d\n", a) //%在fmt里有特殊含意,所以需要前面再加个%转义一下
a, b = 8, 3
a <<= b
fmt.Printf("a<<=b %d\n", a)
a, b = 8, 3
a >>= b
fmt.Printf("a>>=b %d\n", a)
a, b = 8, 3
a &= b
fmt.Printf("a&=b %d\n", a)
a, b = 8, 3
a |= b
fmt.Printf("a|=b %d\n", a)
a, b = 8, 3
a ^= b
fmt.Printf("a^=b %d\n", a)
}三、变量、常量、字面量
3.1、变量类型
3.2、变量声明
Go语言变量必须先声明再使用,所谓使用指读取或修改。 标题声明
var name string
var age int
var isOk bool批量声明
var (
name string
age int
isOk bool
)3.3、变量初始化
如果声明后未显式初始化,数值型初始化0,字符串初始化为空字符串,布尔型初始化为false,引用类型、函数、指针、接口初始化为nil。
var a string="china" //初始化一个变量
var a="china" //类型推断为string
var a,b int=3,7 //初始化多个变量
var a,b="china",7 //初始化多个变量,每个变量都单独地执行类型推断 函数内部的变量(非全局变量)可以通过:=声明并初始化。
a:=3下划线表示匿名变量。匿名变量不占命名空间,不会分配内存,因此可以重复使用。
_=2+43.4、常量
常量在定义时必须赋值,且程序运行期间其值不能改变。
const PI float32=3.14
const(
PI=3.14
E=2.71
)
const(
a=100
b //100,跟上一行的值相同
c //100,跟上一行的值相同
)const(
a=iota //0
b //1
c //2
d //3
)
const(
a=iota //0
b //1
_ //2
d //3
)
const(
a=iota //0
b=30
c=iota //2
d //3
)
const(
_=iota // iota =0
KB=1<<(10* iota) // iota =1
MB=1<<(10* iota) // iota =2
GB=1<<(10* iota) // iota =3
TB=1<<(10* iota) // iota =4
)
const(
a,b=iota+1, iota+2 //1,2 iota =0
c,d //2,3 iota =1
e,f //3,4 iota =2
)3.5、字面量
字面量--没有出现变量名,直接出现了值。基础类型的字面量相当于是常量。
fmt.Printf("%t\n", 04 == 4.00) //用到了整型字面量和浮点型字面量
fmt.Printf("%v\n", .4i) //虚数字面量 0.4i
fmt.Printf("%t\n", '\u4f17' == '众') //Unicode和rune字面量
fmt.Printf("Hello\nWorld\n!\n") //字符串字面量四、变量作用域
对于全局变量,如果以大写字母开头,所有地方都可以访问,跨package访问时需要带上package名称;如果以小写字母开头,则本package内都可以访问。
函数内部的局部变量,仅本函数内可以访问。{}可以固定一个作用域。内部声明的变量可以跟外部声明的变量有冲突,以内部的为准--就近原则。
var (
A=3 //所有地方都可以访问
b=4 //本package内可以访问
)
func foo(){
b:=5 //本函数内可以访问
{
b:=6 //本作用域内可以访问
}
}五、注释与godoc
5.1、注释的形式
单行注释,以//打头。
多行注释有2种形式:
连续多行以//打头,注意多行注释之间不能出现空行。
在段前使用/*,段尾使用*/。
注释行前加缩进即可写go代码。
注释中给定的关键词。NOTE: 引人注意,TODO: 将来需要优化,Deprecated: 变量或函数强烈建议不要再使用。
//Add 2个整数相加
//返回和。
//
//NOTE: 注释可以有多行,但中间不能出现空行(仅有//不算空行)。
func Add(a, b int) int {
return a + b
}
/*
Sub 函数使用示例:
for i:=0;i<3;i++{
Sub(i+1, i)
}
看到了吗?只需要行前缩进,注释里就可以写go代码,是不是很简单。
*/
func Sub(a, b int) int {
return a - b
}
//TODO: Prod 该函数不能并发调用,需要优化
func Prod(a, b int) int {
return a * b
}
//Deprecated: Div 不要再调用了
func Div(a, b int) int {
return a / b
}5.2、注释的位置
针对行的注释在行上方或右侧。函数的上方在func xxx()上方。结构体的注释在type xxx struct上方。包注释在package xxx的上方。一个包只需要在一个地方写包注释,通常会专门写一个doc.go,里面只有一行package xxx和关于包的注释。
// FormatBool, FormatFloat, FormatInt, and FormatUint convert values to strings:
//
// s := strconv.FormatBool(true)
// s := strconv.FormatFloat(3.1415, 'E', -1, 64)
// s := strconv.FormatInt(-42, 16)
// s := strconv.FormatUint(42, 16)
package fmt5.3、go doc
go doc是go自带的命令。
go doc entrance_class/util上述命令查看entrance_class/util包的注释。
5.4、godoc
godoc是第三方工具,可以为项目代码导出网页版的注释文档。安装godoc命令如下
go get -u golang.org/x/tools/cmd/godoc
go install golang.org/x/tools/cmd/godoc@latest启动http服务:
godoc -http=:6060用浏览器访问http://127.0.0.1:6060 ,可以查看go标准库的文档。