〇、Go可以做什么?
学习方向
区块链研发工程师、Go服务器端/游戏软件开发工程师、Go分布式/云计算软件工程师
一、基础知识
1.1 Go程序开发注意事项(⭐⭐⭐)
- Go源代码以“go”为扩展名;
- Go应用程序的执行入口是main()方法;
- Go语言严格区分大小写;
- Go方法由一条条语句构成,每个语句不需要分号(Go语言会在每行后自动加分号),这体现出Go语言的简洁性;
- Go编译器是一行行进行表一的,因此我们一行就写一条语句,不能多条语句写在同一行,否则会报错;
- Go语言定义的变量或者import包如果没有使用到,代码不能编译通过(只要声明的东西或引用的包就一定要用到);
- 大括号成对出现,缺一不可。
1.2 注释(comment)
Go支持C语言风格的/* */块注释,也支持C++风格的//行注释。行注释更通用,块注释主要用于针对包的详细说明或者屏蔽大块的代码。
Go官方推荐使用行注释来注释整个方法和语句。
- 行注释
- 块注释(多行注释)
func main() {
// 行注释规范
// fmt.Println("Hello,world")
fmt.Println("Hello,world")
/*
块注释规范
fmt.Println("Hello,world")
fmt.Println("Hello,world")
*/
fmt.Println("Hello,world")
}
1.3 变量
变量是程序的基本单位,变量相当于内存中的一个存储空间的表示,可以把变量当成一个房间的门牌号,通过门牌号我们可以找到房间,同理,通过变量可以访问到变量的值。
func main() {
// 1.声明变量
var name string
// 2.给变量name赋值
name = "武松"
// 3.使用变量
fmt.Println("姓名=", name)
}
1.3.1 变量使用注意事项(⭐⭐⭐)
-
变量标识内存中的一个存储区域;
-
该区域有自己的名称(变量名)和类型(数据类型);
-
Golang变量使用的三种方式:
第一种:指定变量类型,声明后如果不复制,使用默认值;
var age int fmt.Println("age=", age)
第二种:根据值自行判定变量类型;
var age = 18 fmt.Println("age =", age)
第三种:省略var,注意::=左侧的变量不应该是已经声明过的(类型推导),否则导致编译错误;
age := 18 fmt.Println("age =", age)
-
多变量声明
在编程中,有时我们需要一次性声明多个变量,Golang也提供这种语法。
func main() {
// 指明类型
var n1, n2, n3 int
fmt.Println(n1, ",", n2, ",", n3)
// 自行判定
var n4, n5, n6 = 100, "tom", 11.1
fmt.Println(n4, ",", n5, ",", n6)
// 类型推导
n7, n8, n9 := 100, "tom", 11.1
fmt.Println(n7, ",", n8, ",", n9)
}
1.3.2 变量的数据类型
bit:计算机中最小的存储单位。
byte:计算机中基本存储单元。
Golang的字符串是由字节组成。
类型 | 有无符号 | 占用存储空间 | 表数范围 | 备注 |
---|---|---|---|---|
int8 | 有 | 1字节 | -128~127 | |
int16 | 有 | 2字节 | -215~215-1 | |
int32 | 有 | 4字节 | -231~231-1 | |
int64 | 有 | 8字节 | -263~263-1 | |
unint8 | 无 | 1字节 | 0~255 | |
uint16 | 无 | 2字节 | 0~2^16-1 | |
uint32 | 无 | 4字节 | 0~2^32-1 | |
uint64 | 无 | 8字节 | 0~2^64-1 | |
int | 有 | 32位系统4个字节;64位系统8字节 | -231~231-1;-263~263-1 | |
uint | 无 | 32位系统4个字节;64位系统8字节 | 02^32-1;02^64-1 | |
rune | 有 | 与int32一样 | 等价于int32,标识一个Unicode码 | |
byte | 无 | 与uint8等价 | 当要存储字符时选择byte | |
float32 | 4字节 | -3.403E38~3.403E38 | 单精度 | |
float64 | 8字节 | -1.798E308~1.798E308 | 双精度 | |
bool | 1字节 | 布尔类型 |
字符串(string)类型
字符串就是一串固定长度的字符连接起来的字符序列。Go的字符串是由单个字节连接起来的,Go语言的字符串的字节使用UTF-8编码标识Unicode文本。
// golang中string类型使用
func main() {
var name string = "张三"
fmt.Println("name=", name)
}
字符串使用注意事项
- 字符串一旦赋值,字符串就不能修改;在Go中字符串是不可变的。
- 字符串拼接的时候加号要留在上面。
基本数据类型默认值
数据类型 | 默认值 |
---|---|
整型 | 0 |
浮点型 | 0 |
字符串 | “” |
布尔类型 | false |
1.3.3 基本数据类型的相互转化
Golang和Java/c不同,Go在不同类资那个的变量之间赋值时需要显示转换。也就是说Go中数据类型不能自动转换。
基本语法
表达式T(v)将值v转换成类型T
T:就是数据类型,比如int32、int64、float32等
v:就是需要转换的变量
/*
表达式T(v)将值v转换成类型T
T:就是数据类型,比如int32、int64、float32等
v:就是需要转换的变量
*/
func main() {
var age int = 100
var age2 = float32(age)
fmt.Printf("age=%v,age2=%v\n", age, age2)
}
使用细节 (⭐⭐⭐)
-
Go中,数据类型的转换可以是从表示范围小->表示范围大,也可以是范围大->范围小(需要注意取值范围);
func main() { // 下面代码无法编译通过,需要进行类型转换。 var n1 int32 = 12 var n2 int64 var n3 int8 n2 = n1 + 20 // int32->int64 【编译报错,无法自动转换】 n3 = n1 + 20 // int32->int8【编译报错,无法自动转换】 }
-
被转换的是变量存储数据(值),变量本身的数据类型并没有变化;
-
在转换中,比如将int64转换成int8【-128~127】编译不会报错,只是转换的结果是按溢出处理,与期望结果不同。因此,在转换时需要考虑范围。
func main() {
var age int32 = 999999
var age2 int8 = int8(age)
fmt.Println("age2=", age2) // 编译不会报错,但是结果为【age2=63】,与预期结果不同
}
1.3.4 基本数据类型转string(⭐⭐⭐)
在程序开发过程中,我们经常需要将基本数据类型转换成string类型,或者将string类型转成基本数据类型。
→ 方式1
fmt.Sprintf(“%参数”,表达式) 【推荐使用,较为灵活】
函数介绍:
参数需要和表达式的数据类型相匹配,fmt.Sprintf()会返回转换后的字符串
func main() {
var num1 int = 100
var num2 float64 = 23.899
var b bool = true
var myChar byte = 'a'
var str string // 空字符串
// 使用第一种方式转换fmt.Printf()
str = fmt.Sprintf("%d", num1)
fmt.Printf("str type is %T,str=%q\n", str, str) // 运行结果:【str type is string,str="100"】
str = fmt.Sprintf("%f", num2)
fmt.Printf("str type is %T,str=%q\n", str, str) // 运行结果:【str type is string,str="23.899000"】
str = fmt.Sprintf("%t", b)
fmt.Printf("str type is %T,str=%q\n", str, str) // 运行结果:【str type is string,str="true"】
str = fmt.Sprintf("%c", myChar)
fmt.Printf("str type is %T,str=%q\n", str, str) // 运行结果:【str type is string,str="a"】
}
→ 方式2
使用strconv包的函数
func main() {
var num3 int = 100
var num4 float64 = 23.899
var num5 int = 1234567
var b2 bool = true
// 使用第二种方式strconv函数
str = strconv.FormatInt(int64(num3), 10)
fmt.Printf("str type is %T,str=%q\n", str, str) // 运行结果:【str type is string,str="100"】
/*
说明:
'f'表示格式;
10:表示小数位保留十位;
64:表示这个小数是float64
*/
str = strconv.FormatFloat(num4, 'f', 10, 64)
fmt.Printf("str type is %T,str=%q\n", str, str) // 运行结果:【str type is string,str="23.8990000000"】
str = strconv.Itoa(num5)
fmt.Printf("str type is %T,str=%q\n", str, str) // 运行结果:【str type is string,str="1234567"】
str = strconv.FormatBool(b2)
fmt.Printf("str type is %T,str=%q\n", str, str) // 运行结果:【str type is string,str="true"】
}
1.3.5 string类型转基本数据类型
使用的是strconv包的函数
func main() {
var str string = "true"
var b bool
/*
strconv.ParseBool(str)说明:
1.函数会返回两个值(value bool,err error)
2.我只想获取value bool,不想获取err 所以使用"_"忽略
*/
b, _ = strconv.ParseBool(str)
fmt.Printf("b type is %T,b=%v\n", b, b) // 运行结果:【b type is bool,b=true】
var str2 string = "123456"
var n1 int64
var n2 int
/*
说明:
1.第一个参数表示对应的str字符串
2.第二个参数表示几进制
3.第三个参数表示int的精度
*/
n1, _ = strconv.ParseInt(str2, 10, 64)
fmt.Printf("n1 type is %T,n1=%v\n", n1, n1) // 运行结果:【n1 type is int64,n1=123456】
// 类型转换
n2 = int(n1)
fmt.Printf("n2 type is %T,n2=%v\n", n2, n2) // 运行结果:【n2 type is int,n2=123456】
var str3 string = "123.99999"
var f1 float64
f1, _ = strconv.ParseFloat(str3, 64)
fmt.Printf("f1 type is %T,f1=%v\n", f1, f1) // 运行结果:【f1 type is float64,f1=123.99999】
}
其他说明:因为返回的都是int64或者float64,如果希望得到int32、float32需要进行类型转换处理。
注意事项:
再将string类型转换成基本数据类型时,要确保string类型能够进行有效的转换,比如我们可以将“123”转成一个整数,但是不可以将“hello”转成一个整数,如果这样做,Go会直接将其转成0。
var str4 string = "hello"
var n3 int64
n3, _ = strconv.ParseInt(str4, 10, 64)
fmt.Printf("n3 type is %T,n3=%v\n", n3, n3) // 运行结果:【n3 type is int64,n3=0】
1.4 指针
1.4.1基本介绍
- 基本数据类型,变量存的就是值,也叫值类型;
- 获取变量的地址,用&,比如:var num int,获取num的地址就是:#
-
指针类型,变量存的就是一个地址,这个地址指向的空间存的才是值,比如:var ptr *int=#
-
获取指针类型所指向的值,使用:*,比如:var ptr *int,使用 *ptr获取ptr指向的值;
func main() {
// 基本数据类型在内存中的布局
var i int = 10
// 获取变量i的地址,&i
fmt.Println("变量i的地址=", &i) // 打印:【变量i的地址= 0xc00000a0b8】
/*
说明:
1.ptr是一个指针变量
2.ptr的类型是*int
3.ptr本身的值是&i
*/
var ptr *int = &i
// 获取ptr的值
fmt.Printf("ptr=%v\n", ptr) //打印:【ptr=0xc00000a0b8】
// 获取ptr的地址
fmt.Println("ptr的地址=", &ptr) // 打印:【ptr的地址= 0xc00004e028】
// 获取ptr指向的值
fmt.Println("ptr指向的值=", *ptr) // 打印:【ptr指向的值=10】
}
1.4.2指针细节说明
- 值类型,都有对应的指针类型,形式为*数据类型,比如:int的对应指针就是 *int,float32对应的指针就是 *float32,以此类推;
- 值类型包括:基本数据类型int系列、float系列、bool、string、数组和结构体struct。
1.4.3 案例演示
-
写一个程序,获取int变量的num地址,并现在在终端;
-
将num的地址赋值给指针ptr,并通过ptr去修改num的值。
func main() { var num int = 100 fmt.Printf("变量num的地址=%v\n", &num) fmt.Println("num=", num) var ptr *int ptr = &num *ptr = 99 fmt.Println("num=", num) }
1.4.4 值类型和引用类型
分类
- 值类型:基本数据类型int系列、float系列、bool、string、数组和结构体struct;
- 引用类型:指针、slice切片、map、管道chan、interface等都是引用类型。
使用特点
- 值类型:变量直接存储值,内存通常在栈中分配(值类型通过逃逸分析可能会跑到堆区);
- 引用类型:变量存储的就是一个地址,这个地址对应的空间才是真正的存储数据(值),内存通常在堆上分配,当没有任何变量引用这个地址时,改地址对应的数据空间就成为一个垃圾,由GC来回收。
1.5 系统保留关键字
在Go中,为了建华代码编译过程中对代码的的解析,其定义的保留关键字只有25个,详见如下:
break | default | func | interface | select |
---|---|---|---|---|
case | defer | go | map | struct |
chan | else | goto | package | switch |
const | fallthrough | if | range | type |
continue | for | import | return | var |
1.6系统预定义标识符
除了保留关键字外,Go还提供了36个预定的标识符,其中包括基础数据类型和系统内嵌函数:
append | bool | byte | cap | close | complex |
---|---|---|---|---|---|
complex64 | complex128 | uint16 | copy | false | float32 |
float64 | imag | int | int8 | int16 | uint32 |
int32 | int64 | iota | len | make | new |
nil | panic | uint64 | println | real | |
recover | string | true | uint | uint8 | uinprt |
1.7 命名规范
1.7.1 标识符概念
Golang对各种变量、方法、函数等命名时使用的字符序列称为标识符,只要是可以起名字的地方都叫标识符。
1.7.2标识符命名规范(⭐⭐⭐)
- 由26个应为字母大小写组成,0~9,"_"组成;
- 数字不可以开头;
- Golang中严格区分大小写;
- 标识符不能包含空格;
- 下划线"_"本身在Go中是一个特殊标识符,称为空标识符。可以代表任何其他的标识符,但是他对应的值会被忽略(比如:忽略某个返回值)。所以仅能被作为占位符使用,不能作为标识符使用。
- 不能以系统保留关键字作为标识符,比如:break、if等…
1.7.3 注意事项
- 包名:和package名字和目录保持一致,尽量采取有意义的包名,不要和标准库有冲突;
- 变量名、函数名、常量名:采用驼峰写法;
- 如果变量名、函数名、常量名首字母大写,则可以被其他包访问;如果首字母小写,则只能在本包中使用(注:可以理解为首字母大写是公有的(public),首字母小写是私有的(private)),在Golang中没有public和private关键字
1.8运算符
运算符是一种特殊符号,用于表示数据的运算、赋值和比较等(类型:算数运算符、赋值运算符、比较运算符、逻辑运算符、位运算符、其他运算符);在Golang中,没有三元运算符,使用if…else…
细节说明
- Go中的自增自减只能当成一个独立的语言使用,不能这样使用:b := a++ 或 b := a-- ;
- Go的++和–只能卸载变量的后面,不能写在变量的前面,即:只有a++或a–,没有++a或–a ;
- Go的设计者去除了C/Java中的自增自减容易混淆的写法(强制性),使Golang更加简洁统一。