【声明】
非完全原创,部分内容来自于学习其他人的理论和B站视频。如果有侵权,请联系我,可以立即删除掉。
一、Go语言简介1、 发展史
2009年11月10日,Go语言正式发布,它是一种强静态类型、编译型语言,它专对多处理器系统应用程序的编程进行了优化,对于对于高并发,多线程的开发场景具有天然的优势
1.1 优势
- 可以直接编译成机器码,不依赖其他库
- 丰富的标准库,特别是网络库非常强大
- 内置runtime,支持垃圾回收
1.2 应用场景
- 服务器编程,例如处理日志、数据打包、虚拟机处理、文件系统等
- 网络编程,包括Web应用、API应用、下载应用
- 内存数据库,如google开发的groupcache,couchbase的部分组建
- 云平台,例如现目前很火爆的k8s 也是利用go语言进行开发完成
- 分布式系统,数据库代理器等
1、 安装Go语言
1.1 下载安装包
官网下载网址: https://www.golangtc.com/download
国内下载地址: https://studygolang.com/dl
中文在线文档: https://studygolang.com/pkgdoc
1.2 win版本安装
一般有zip压缩包和msi的安装方式:
- zip解压就可以使用,但是需要自行配置go语言环境
- msi安装之后,会自动设置环境变量
安装的路径中不应该有中文,否则会导致程序找不到路径
1.3 确认安装成功
go versiongo env
2、 go语言标准命令
安装了go语言之后,就直接可以使用其标准命令来处理Go语言代码,常见的go语言代码的命令和工具有:
build:用于编译给定的代码包或Go语言源码文件及其依赖包。
clean:用于清除执行其他go命令后遗留的目录和文件。
doc:用于执行godoc命令以打印指定代码包。
env:用于打印Go语言环境信息。
fix:用于执行go tool fix命令以修正给定代码包的源码文件中包含的过时语法和代码调用。
fmt:用于执行gofmt命令以格式化给定代码包中的源码文件。
get:用于下载和安装给定代码包及其依赖包(提前安装git或hg)。
list:用于显示给定代码包的信息。
run:用于编译并运行给定的命令源码文件。
install:编译包文件并编译整个程序。
test:用于测试给定的代码包。
tool:用于运行Go语言的特殊工具。
version:用于显示当前安装的Go语言的版本信息。
3、 安装IDE
go语言安装包安装之后,编译代码时,需要通过命令提示符进入代码所在路径下进行编译,不方便代码的管理。为了便于开发,一般需要选择一款开发工具,常见的有:
- LiteIDE:一款开源、跨平台的轻量级 Go 语言集成开发环境(IDE)
- eclipse:需要下载插件
- Goland:由 JetBrains 公司开发的一个新的商业 IDE,提供了针对Go语言的编码辅助和工具集成。
一般来说,使用免费的liteIDE可以满足日常使用,下载网址:http://liteide.org/cn/。windows版本直接安装即可。
4、 go语言的Hello world
如下,是go语言版本的Hello World。由于此处只有一个go文件,因此文件的开头package必须声明一个main的包名,并且在该包中包含一个叫main()的函数作为go语言可执行程序的起点。
//HelloWorld.go
package main
import ("fmt")
func main() {
fmt.Println("Hello World")
}
Printlnfmt
funcmain
进入到对应的目录下即可编译和运行
1、 命名
命名规则:必须以一个字母或下划线开头,后面可以跟任意数量的字母、数字或下划线,且不能与关键字重名。命名的规则和C语言、Java一样。
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 |
另外还有30多个预定义的名字:
内建常量:
true false iota nil
内建类型:
int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptr
float32 float64 complex128 complex64
bool byte rune string error
内建函数:
make len cap new append copy close delete
complex real imag
panic recover
2、 变量
变量是程序运行期间可以改变的量,相当于是对一块数据存储空间的命名,程序可以通过定义一个变量来申请一块数据存储空间,之后可以通过引用变量名来使用这块存储空间。
2.1 变量的声明
var类型 变量名
//定义单个变量
var v1 int
//同时定义多个变量:只能同一种类型
var v2, v3 int
//同时定义多个变量:变量可以不同类型
var (
v4 int
v5 bool
)
2.2 变量初始化
var:=
package main
import (
"fmt"
"reflect"
)
func main() {
var v1 int = 1 // 普通初始化的方式
var v2 = 2 // 编译器自动推导类型的初始化方式
v3 := 3 //编译器自动推导类型的初始化方式:不用写var关键字
v4 := 4.0
v5 := false
fmt.Println("v3 type is ", reflect.TypeOf(v3))
fmt.Println("v4 type is ", reflect.TypeOf(v4))
fmt.Printf("v5 type is %T\n", v5)
fmt.Printf("v1+v2 type is %T\n", v1+v2)
}
var v1 intv1:=1:=
2.3 变量赋值
go语言赋值类似于python,可以多重赋值,如下:
var v1 int = 1 //初始化时赋值
//先声明后赋值
var v2, v3, v4 int
v2 = 2
v3, v4 = 3, 4 //多重赋值
v5 := 5 //使用:=声明且赋值
v3, v5 = v5, v3 //多重赋值实现值交换
_, v2 = 3, 4 //匿名变量`_`是个特殊的变量名,其值会被丢弃
3、 常量
常量是指编译期间就已知且不可改变的值。常量可以是数值类型(包括整型、浮点型和复数类型)、布尔类型、字符串类型等。
3.1 字面常量
直接写在代码中的数字,文字等代码文本。如下示例在C语言中可直接独立存在的字面常量,但该写法在go语言中会报错(定义未使用)
int main()
{
true; //布尔类型的字面常量
'a'; //字符字面常量,本质上是整数对应的ASCII编码
"123abc你好"; //字符串字面常量,本质是一个地址
666uL; //unsigned long字面常量
3.14F; //float字面常量
return 0;
}
字面常量经常出现在硬编码中。硬编码是指,将数据直接写入到代码中进行编译开发的方式,如没有mybatits前,将sql语句写入到jdbc代码里。其主要的缺陷在于,如果需要变更,则需要修改源代码。
非硬编码,也指软编码,是指将数据与源代码解耦,使代码更加合理的方式,如将参数使用变量来表达便于修改等等
const
varconst
//定义单个常量
const v1 = 3.14 //浮点常量, 自动推导类型
//同时定义多个常量:只能同一种类型
const v2, v3 int = 2, 3
//同时定义多个常量:常量可以不同类型
const (
v4 float64 = 1.56
v5 bool = true
)
iota
iotaconst
package main
import (
"fmt"
)
func main() {
const (
i = iota //i = 0
j = iota //j = 1
)
//每遇到const, iota将会重置为0
const (
a = iota + 11 //a = 0 +11
b = iota * 10 //b = 1 *10
c = iota * 5 + 1 //c = 2 *5+1
)
const m = iota //m = 0
fmt.Printf("i = %d, j = %d\n", i, j)
fmt.Printf("a = %d, b = %d, c = %d\n", a, b, c)
fmt.Printf("m = %d\n", m)
}
4、 基础数据类型
Go语言内置以下这些基础类型
类型 | 名称 | 长度 | 零值 | 说明 |
---|---|---|---|---|
bool | 布尔类型 | 1 | false | 其值不为真即为家,不可以用数字代表true或false |
byte | 字节型 | 1 | 0 | uint8别名 |
rune | 字符类型 | 4 | 0 | 专用于存储unicode编码,等价于uint32 |
int, uint | 整型 | 4或8 | 0 | 32位或64位 |
int8, uint8 | 整型 | 1 | 0 | -128 ~ 127, 0 ~ 255 |
int16, uint16 | 整型 | 2 | 0 | -32768 ~ 32767, 0 ~ 65535 |
int32, uint32 | 整型 | 4 | 0 | -21亿 ~ 21 亿, 0 ~ 42 亿 |
int64, uint64 | 整型 | 8 | 0 | |
float32 | 浮点型 | 4 | 0.0 | 小数位精确到7位 |
float64 | 浮点型 | 8 | 0.0 | 小数位精确到15位 |
complex64 | 复数类型 | 8 | ||
complex128 | 复数类型 | 16 | ||
uintptr | 整型 | 4或8 | ⾜以存储指针的uint32或uint64整数 | |
string | 字符串 | “” | utf-8字符串 |
4.1 布尔类型
truefalse
var v1 bool
v1 = true
v2 := (1 == 2) // v2也会被推导为bool类型
//布尔类型不能接受其他类型的赋值,不支持自动或强制的类型转换
var b bool
b = 1 // err, 编译错误
b = bool(1) // err, 编译错误
4.2 整型
使用自动推导时,整数会自动推导为int类型
package main
import (
"fmt"
)
func main() {
var v1 int32
v1 = 123
v2 := 64 // v1将会被自动推导为int类型
fmt.Printf("v1 type is %T\n", v1)
fmt.Printf("v2 type is %T\n", v2)
}
4.3 浮点型
使用自动推导时,小数会自动推导为float64类型
package main //必须有一个main包
import "fmt"
func main() {
//声明变量
var f1 float32
f1 = 3.14
fmt.Println("f1 = ", f1)
//自动推导类型
f2 := 3.14
fmt.Printf("f2 type is %T\n", f2) //f2 type is float64
//float64存储小数比float32更准确
}
4.4 字符类型
charCharacterbyterune
'\n'
package main //必须有一个main包
import "fmt"
func main() {
var ch byte //声明字符类型
ch = 97
//fmt.Println("ch = ", ch)
//格式化输出,%c以字符方式打印,%d以整型方式打印
fmt.Printf("%c, %d\n", ch, ch)
ch = 'a' //字符, 单引号
fmt.Printf("%c, %d\n", ch, ch)
//大写转小写,小写转大写, 大小写相差32,小写大
fmt.Printf("大写:%d, 小写:%d\n", 'A', 'a')
fmt.Printf("大写转小写:%c\n", 'A'+32)
fmt.Printf("小写转大写:%c\n", 'a'-32)
}
4.5 字符串类型
string'\0'
package main //必须有一个main包
import "fmt"
func main() {
var str1 string //声明变量
str1 = "abc" // 由'a'、'b'、'c'和'\0'组成了一个字符串
fmt.Println("strl = ", str1)
//自动推导类型
str2 := "mike"
fmt.Printf("str2 类型是 %T\n", str2)
//内建函数,len()可以测字符串的长度,有多少个字符
fmt.Println("len(str2) = ", len(str2))
}
4.6 字符和字符串的区别
""\0
package main //必须有一个main包
import "fmt"
func main() {
var ch byte
var str string
ch = 'a'
fmt.Println("ch =", ch)
str = "a" // 由'a'和'\0'组成了一个字符串
fmt.Println("str = ", str)
str = "hello go"
//只想操作字符串的某个字符,从0开始操作
fmt.Printf("str[0] = %c, str[1] = %c\n", str[0], str[1])
}
4.7 复数类型
复数实际上由两个实数(在计算机中用浮点数表示)构成,一个表示实部(real),一个表示虚部(imag)
package main //必须有一个main包
import "fmt"
func main() {
var t complex128 //声明
t = 2.1 + 3.14i //赋值
fmt.Println("t = ", t)
//自动推导类型
t2 := 3.3 + 4.4i
fmt.Printf("t2 type is %T\n", t2)
//通过内建函数,取实部和虚部
fmt.Println("real(t2) = ", real(t2), ", imag(t2) = ", imag(t2))
}
5、 类型转换、类型别名
5.1 类型转换
Go语言中不允许隐式转换,所有类型转换必须显式声明,而且转换只能发生在两种相互兼容的类型之间。
package main //必须有一个main包
import "fmt"
func main() {
var flag bool
flag = true
fmt.Printf("flag = %t\n", flag)
//bool类型不能转换为int,这种不能转换的类型,叫不兼容类型
//fmt.Printf("flag = %d\n", int(flag))
//0就是假,非0就是真
//整型也不能转换为bool
//flag = bool(1)
var ch byte
ch = 'a' //字符类型本质上就是整型
var t int
t = int(ch) //类型转换,把ch的值取出来后,转成int再给t赋值
fmt.Println("t = ", t)
}
5.2 类型别名
package main //必须有一个main包
import "fmt"
func main() {
//给int64起一个别名叫bigint
type bigint int64
var a bigint // 等价于var a int64
fmt.Printf("a type is %T\n", a)
type (
long int64
char byte
)
var b long = 11
var ch char = 'a'
fmt.Printf("b = %d, ch = %c\n", b, ch)
}
fmt
6.1 格式说明
printf
格式 | 含义 |
---|---|
%% | 一个%字面量 |
%b | 一个二进制整数值(基数为2),或者是一个(高级的)用科学计数法表示的指数为2的浮点数 |
%c | 字符型。可以把输入的数字按照ASCII码相应转换为对应的字符 |
%d | 一个十进制数值(基数为10) |
%e | 以科学记数法e表示的浮点数或者复数值 |
%E | 以科学记数法E表示的浮点数或者复数值 |
%f | 以标准记数法表示的浮点数或者复数值 |
%g | 以%e或者%f表示的浮点数或者复数,任何一个都以最为紧凑的方式输出 |
%G | 以%E或者%f表示的浮点数或者复数,任何一个都以最为紧凑的方式输出 |
%o | 一个以八进制表示的数字(基数为8) |
%p | 以十六进制(基数为16)表示的一个值的地址,前缀为0x,字母使用小写的a-f表示 |
%q | 使用Go语法以及必须时使用转义,以双引号括起来的字符串或者字节切片[]byte,或者是以单引号括起来的数字 |
%s | 字符串。输出字符串中的字符直至字符串中的空字符(字符串以’\0‘结尾,这个’\0’即空字符) |
%t | 以true或者false输出的布尔值 |
%T | 使用Go语法输出的值的类型 |
%U | 一个用Unicode表示法表示的整型码点,默认值为4个数字字符 |
%v | 使用默认格式输出的内置或者自定义类型的值,或者是使用其类型的String()方式输出的自定义值,如果该方法存在的话 |
%x | 以十六进制表示的整型值(基数为十六),数字a-f使用小写表示 |
%X | 以十六进制表示的整型值(基数为十六),数字A-F使用小写表示 |
6.2 输出
package main //必须有一个main包
import "fmt"
func main() {
a := 10
b := "abc"
c := 'a'
d := 3.14
//%T操作变量所属类型
fmt.Printf("%T, %T, %T, %T\n", a, b, c, d)
//%d 整型格式
//%s 字符串格式
//%c 字符个数
//%f 浮点型个数
fmt.Printf("a = %d, b = %s, c = %c, d = %f\n", a, b, c, d)
//%v自动匹配格式输出
fmt.Printf("a = %v, b = %v, c = %v, d = %v\n", a, b, c, d)
}
6.3 输入
package main //必须有一个main包
import "fmt"
func main() {
var a int //声明变量
fmt.Printf("请输入变量a: ")
//阻塞等待用户的输入
//fmt.Scanf("%d", &a) //别忘了&
fmt.Scan(&a)
fmt.Println("a = ", a)
}
四、运算符
1、 算术运算符
运算符 | 术语 | 示例 | 结果 |
---|---|---|---|
+ | 加 | 10 + 5 | 15 |
- | 减 | 10 - 5 | 5 |
* | 乘 | 10 * 5 | 50 |
/ | 除 | 10 / 5 | 2 |
% | 取模(取余) | 10 % 3 | 1 |
++ | 后自增,没有前自增 | a=0 a++ | a=1 |
– | 后自减,没有前自减 | a=1 a– | a=0 |
2、 关系运算符
运算符 | 术语 | 示例 | 结果 |
---|---|---|---|
== | 相等于 | 4 == 3 | false |
!= | 不等于 | 4 != 3 | true |
< | 小于 | 4 < 3 | false |
> | 大于 | 4 > 3 | true |
<= | 小于等于 | 4 <= 3 | false |
>= | 大于等于 | 4 >= 1 | true |
3、 逻辑运算符
运算符 | 术语 | 示例 | 结果 |
---|---|---|---|
! | 非 | !a | 如果a为假,则!a为真; |
&& | 与 | a && b | 如果a和b都为真,则结果为真,否则为假。 |
|| | 或 | a || b | 如果a和b有一个为真,则结果为真,二者都为假时,结果为假。 |
4、 位运算符
运算符 | 术语 | 说明 | 示例 |
---|---|---|---|
& | 按位与 | 参与运算的两数各对应的二进位相与 | 7 & 8 结果为 0 |
| | 按位或 | 参与运算的两数各对应的二进位相或 | 7 | 8 结果为 15 |
^ | 异或 | 参与运算的两数各对应的二进位相异或,当两对应的二进位数字不同时,结果为1 | 7 ^ 8 结果为 15 |
<< | 左移 | 左移n位就是乘以2的n次方。 左边丢弃,右边补0。 | 1 << 3 结果为 8 (1*2^3) |
>> | 右移 | 右移n位就是除以2的n次方。 右边丢弃,左边补位。 | 8 >> 3 结果为1 |
5、 赋值运算符
运算符 | 说明 | 示例 |
---|---|---|
= | 普通赋值 | c = a + b 将 a + b 表达式结果赋值给 c |
+= | 相加后再赋值 | c += a 等价于 c = c + a |
-= | 相减后再赋值 | c -= a 等价于 c = c - a |
*= | 相乘后再赋值 | c *= a 等价于 c = c * a |
/= | 相除后再赋值 | c /= a 等价于 c = c / a |
%= | 求余后再赋值 | c %= a 等价于 c = c % a |
<<= | 左移后赋值 | c <<= 2 等价于 c = c << 2 |
>>= | 右移后赋值 | c >>= 2 等价于 c = c >> 2 |
&= | 按位与后赋值 | c &= 2 等价于 c = c & 2 |
^= | 按位异或后赋值 | c ^= 2 等价于 c = c ^ 2 |
|= | 按位或后赋值 | c |= 2 等价于 c = c | 2 |
6、 其他运算符
运算符 | 术语 | 示例 | 说明 |
---|---|---|---|
& | 取地址运算符 | &a | 变量a的地址 |
* | 取值运算符 | *a | 指针变量a所指向内存的值 |
7、 运算符优先级
在Go语言中,一元运算符拥有最高的优先级,二元运算符的运算方向均是从左至右。
下表列出了所有运算符以及它们的优先级,由上至下代表优先级由高到低:
优先级 | 运算符 |
---|---|
7 | ^ ! |
6 | * / % << >> & &^ |
5 | + - |
4 | == != < <= >= > |
3 | <- |
2 | && |
1 | || |
package main //必须有一个main包
import "fmt"
func main() {
fmt.Println("4 > 3 结果:", 4 > 3)
fmt.Println("4 != 3 结果:", 4 != 3)
fmt.Println("!(4 > 3) 结果:", !(4 > 3))
fmt.Println("!(4 != 3) 结果:", !(4 != 3))
//&& 与, 并且,左边右边都为真,结果才为真, 其它都为假
fmt.Println("true && true 结果:", true && true)
fmt.Println("true && false 结果:", true && false)
// ||, 或者, 左边右边都为假,结果才为假,其它都为真
fmt.Println("true || false 结果:", true || false)
fmt.Println("false || false 结果:", false || false)
a := 11
fmt.Println("0 <= a && a <= 10 结果为:", 0 <= a && a <= 10)
}