1 Go语言介绍
1 golang--》Go---》谷歌公司 2009年
golang:指go语言,指的go的sdk
goland:软件,ide:集成开发环境 Java写的
2 Go是静态强类型语言
静态:需要编译再执行
C、C#、Java:编译成不同平台的可执行文件在不同平台执行
c语言:编译慢
Go:编译快、并且可跨平台编译
动态:python php nodejs
需要一个解释器
边解释边运行
对运维很麻烦
pyinstaller 弄成可执行文件
强类型:
不同类型之间不允许直接运算(所以要强制类型转换)
go如何强制类型转换:显式类型转换
Java:可以字符串+数字 但是是强类型语言--隐式类型转换、内部自动转换
弱类型:js
比如可以:字符串+数字
3 Go语言特性
跨平台的编译型语言(交叉编译)
语法接近C语言
管道(channel),切片(slice),并发(routine)--》线程池+协程
有垃圾回收的机制(GC机制)
支持面向对象和面向过程的编程模式
(继承,封装,多态)写法有点古怪
4 Go语言发展(版本/特性)
// go语言也是用c写的
//java,python都是用c写的
2012年3月28日 go1 —— 稳定版版的发布
2015年8月19日 go1.5 —— 实现的架构变化,同时保留了和旧版本的兼容性,本次更新中移除了”最后残余的C代码”---》自举
2018年8月24日 go1.11 —— modules支持,摒弃掉go path的包管理
2020 年 2 月 go 1.14— — 现在 Go Module 已经可以用于生产环境
至今:1.17.6 开始支持泛型(额外操作)
5 go应用领域
-服务端开发 高并发
-微服务方向
-区块链开发 第一款开源的区块链软件是用go写的
-自动化运维 docker,k8s二开(docker、k8s是go写的,对go友好)
-云平台
-各个互联网公司都会招go开发
-中小型公司跟风
-前景:很广阔
-以后自身有很好的未来:python、go、java(热门语言)都要会
-go简单易学
2 静态和动态语言
c语言:按照c的语法写代码---->把源代码拿到Linux机器编译--》编译成Linux的可执行文件---》在Linux平台运行
java:一处编码处处运行,编译型语言
-java的编译不是编译成可执行文件----》字节码文件,jar,war---》不能直接运行在操作系统之上(不是可执行文件)
-java虚拟机:不同平台有不同平台的虚拟机,字节码文件运行在虚拟机之上
-java的跨平台本质是不同平台装了不同平台的虚拟机---》有的人把它当成解释器
python:解释型----》python的源代码,运行在不同平台的解释器之上----》天然跨平台
php:解释型:php的解释器
nodejs: node环境
go:编译型,交叉编译(跨平台编译),只需要拿到编译好的可执行文件,直接运行即可
3 go开发环境搭建
// 搭建开发环境
// go的运行环境:不需要搭建---》可执行文件
// go的sdk----》内置函数,包,编译go源码(编译成可执行文件)
-1.17 最新 ,向下兼容
-下载地址:https://golang.google.cn/dl/
-go1.17.6.windows-amd64.msi 一路下一步
-安装完成后,会把安装路径加入到环境变量
-go 命令,可以找到(如果没有装sdk,go可执行文件是没有的)
// 集成开发工具:推荐 goland
-goland:推荐,收费,免费试用30天,老版本可以卡bug,无限试用30天
-学生免费(教育邮箱)
-开源软件作者免费(github开源持续多长时间提交代码)
-花钱:单软件,多软件授权,多账号
-破解:pycharm如何破,这个一样
-下载地址:
-https://www.jetbrains.com/zh-cn/go/download/other.html---》2021.1--》好破解
-goland,pycharm,webstorm。。一家公司出的 Jetbrains
-快捷键都一样,使用习惯都一样
-安装:一路下一步
-vs code
-免费,有部分公司用,不涉及到版权问题
-vim
-装各种插件
// 验证环境搭建
-打开cmd创建,输入
-go version // 查看版本信息
-go env // 查看go的环境变量
4 第一个go程序
// 新建的go项目内,有go.mod 文件,后面会讲,做包管理的
// 代码写好---》go是编译型语言----》编译成可执行文件----》运行可执行文件
// 运行方法:
- go build go文件名字 // 编译go文件,编译成 go文件名字.exe
- go文件名字.exe 可执行文件运行即可
// 开发阶段----》编译--》运行,比较麻烦,所以:
-goland提供了,编译并运行---》右键---》run
-原生提供了一个命令 (编译并运行的命令),但是编译后的文件,不在项目根路径下
-go run go文件名字
// ************第一个helloworld的代码***********
package main // 指定包名,任何一个go文件都要有这句话,包名可以不一样,目前必须叫main
import "fmt" //导入内置包,fmt包,只要使用了fmt包,会自动导入,goland自动导入的,如果其他编辑器,需要手动导入
func main() { // 定义一个函数,函数名叫 main,目前必须叫main
fmt.Println("hello world") // 真正的在控制台输出 hello world,必须用双引号
}
// 第一行,必须指定是main包
// 需要导入fmt包
// 程序要运行,必须写一个main函数,在main函数中打印helloworld
// 注意:go的项目入口:必须是main包下的main函数
// fmt.Println(a...) 是 goland给提示的东西,其实根本不存在,函数的参数提示,不用关注
5 语法和命名规范
// 第一行必须是包名
// 程序要运行,必须是main包下的main函数
-一个项目中有一个main包,有两个main函数,它就不能运行,以后写项目肯定不能有俩main函数
-学基础阶段,可以在一个项目下有多个main函数,但是必须以file形式运行,不能以包形式运行
// 包导入,goland可以自动导入,(后期可以手动导入)
// go build 只编译(在什么平台下就编译成什么平台的可执行文件)----》交叉编译
// go run 编译并运行
5.1 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
// func 定义函数
// import 导入包
// package 声明包名
// var 定义变量的关键字
// 关键字不能作为变量的名字
5.2 37个保留字(对应内建的常量、类型和内置函数)
内建常量: 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
// 以后定义变量时,不能以数字开头,可以使用数字字母下划线组成的字符串来定义
// 变量的大小写,有特殊含义,区分大小写
// 变量定义推荐用驼峰体
-AgeOfPerson go语言和java语言推荐,python不推荐
-age_of_person 下划线方式,不推荐(go不推荐,python推荐)
// go文件的名字,建议使用下划线(参照源码)
-java语言中:变量和文件名都推荐用驼峰
-Python中:变量名和文件名都推荐用下划线
6 变量定义和使用
6 个点
-变量完整定义
-变量类型推导
-变量简略声明
-变量的使用,修改值,打印值
-同时定义多个变量
-变量要先定义,在使用,并且只能定义一次
// 变量的定义和使用
package main
import "fmt"
//var name = "lqz" // 作用域范围是全局,所有函数内部都可以使用
func main() {
// 方式一:完整定义 var关键字 变量名 类型 = 变量值
var NameOfCx string = "cx" // 定义不使用会报错、编译阶段报错
fmt.Println(NameOfCx)
var age int = 19
fmt.Println(age)
// 方式二:类型推导(不需要写类型) var关键字 变量名 = 变量值
var age2 = 19 // 没写类型、是推导出来的、也是固定不能改变
fmt.Println(age2)
var NameOfCx2 = "cx"
fmt.Println(NameOfCx2)
// 如何查看变量类型:Printf
fmt.Printf("变量的类型:%T,变量值:%s", NameOfCx2,NameOfCx2)
// 方式三:简略声明 变量名 := 变量值
//age = 19 // 报错 变量没有定义
age3 := 19
fmt.Println(age3)
fmt.Printf("%T %d", age3, age3)
// 变量的使用:修改值、打印值
var name string = "cx"
// 修改值 只能相同类型修改、在定义阶段就定义了类型、不能改类型
name = "wyz"
fmt.Println(name)
//变量可以先定义再赋值
var age4 int // 只能使用方式一定义方式、不能推导
age4 = 100
fmt.Println(age4)
// 一行同时定义多个变量:推导
var name5, age5, gender5 = "cx", 19, "男"
fmt.Println(name5, age5, gender5)
// 一行同时定义多个变量:简略声明
name6, age6, gender6 := "cx", 19, "男"
fmt.Println(name6, age6, gender6)
// 一行同时定义多个变量:var()
var (
name7 = "cx"
age7 = 19
gender7 = "男"
)
fmt.Println(name7, age7, gender7)
// 变量要先定义 然后使用 并且只能定义一次
// 使用简略声明可以定义多次,但是实际是修改值
var age8 = 19
name8,age8 := "cx",20 // 有定义、有修改、修改的定义是修改
fmt.Println(age8, name8)
}
7 变量类型
// 基础数据类类型
-数字
-整型
-int
-int8
-int16
-int32
-int64
-正整数:无符号整型
-uint
-uint8
-uint16
-uint32
-uint64
-浮点型
-float32
-float64
-复数(正常开发中用不到)
-complex128
-complex64
-字符串
-string
-双引号或三引号包裹 (单引号不行:单引号表示数字)
-布尔
-bool
-true false (都是小写)
-byte:uint8 的别名
-rune:int32 的别名
// 复合数据类型
-数组
-切片
-map
// 高级数据类型
-自定义的类型
-函数类型
-指针类型
// 基础的变量类型
package main
func main() {
// 1 整型(表示正负整数 和 0)
// var age int = 19
// int8 和其他区别在于,表示整数的范围不一样
// var age int8 = -128
// 一个int8 占8个比特位,8个小格只能放0或1,一个字节,所有它有2的8次方中变化,表示数字的大小2的7次方-1种变化
// 正负2的7次方-1 -128----+127
// int16 :正负2的15次方-1
// int32:正负2的31次方-1
// int64:正负2的63次方-1
// int :分平台,在32位机器,表示int32,在64位机器表示int64
// 以后,如果要定义一个变量,表示人的年龄
// var age int = 9223372036854775807
// fmt.Println(age)
// 2 无符号整型
// var age uint =19
// fmt.Println(age)
// uint8: 2的8次方-1 0---255之间
// var age uint8=255
// fmt.Println(age)
// uint16:2的16次方-1
// uint32:2的32次方-1
// uint64:2的63次方-1
// uint 在32位机器是 uint32,在64位机器是uint64
// 3 浮点型(小数),表示精度不一样
// var salary float32= 10.123456789 // 小数点后6位
// var salary2 float64= 10.123456789123456789 // 小数点后15位
// fmt.Println(salary)
// fmt.Println(salary2)
// 4 复数 ---》有实部6 和 虚部 7
// var c complex64= 6 + 7i
// var d complex64= 2 + 3i
// fmt.Println(c+d)
// 结果:实部相加、虚部相加
// 5 字符串---》用双引号或反引号包裹---》反引号可以换行---->等同于python的三引号
// var name = "lqz \n" +"is \n" + "nb"
// var name2 = `彭于晏
// is
// very
// handsome`
// fmt.Println(name)
// fmt.Println(name2)
// 6 单引号,表示的类型是什么? 数字类型,int32,这个字符对应的unicode编码的数字,所以单引号只能放一个字符
//var a ='A' // unicode编码你对应的数字
//var a int32='A' // unicode编码你对应的数字
//fmt.Println(a)
//fmt.Printf("a的类型是:%T",a) // a的类型是int32,它能够表示一个字符
// 7 布尔类型---->if判断中经常用到
//var b bool = true
//var b1 bool = false
//fmt.Println(b)
//fmt.Println(b1)
// 8 byte:uint8 的别名 -rune:int32 的别名
//var a byte ='1' // 最大长度 1个字节,8个比特位,255种变化,只能表示ascii
//var b rune ='你' // 4个字节,表示一个字符,可以放所有的象形文字
//fmt.Println(a)
//fmt.Println(b)
}
/*
Java与Go数字类型比较:
java: byte short int long float double
go: int8 int16 int32 int64 float32 float64
python:int float 不是基础数据类型,是对象
*/
8 常量和iota
// 常量:不变的量、定义后就不变了
//
package main
func main() {
// 常量定义格式:
// 1、const关键字 常量名 类型 = 值
// 2、const关键字 常量名 = 值
const name string="cx"
const age = 19
// 同时定义多个常量
const name2, age2 = "cx", 19
const (
name3 = "cx"
age3 = 18
)
const (
a4 = 1
b4 // 如果不赋值则遵从上面的赋值、相当于b4 = 1
c4
)
// iota:是个自建常量 每换一行都会自增
const (
a5 = iota // 等同于 a5=0
b5
c5
)
const (
a6 = iota
b6 = 100
c6
d6
e6 = iota
) // 0 100 100 100 4
// 注意:
//同时定义多个常量,如果下一行只写常量名,遵从上一行的赋值方式
// iota每换一行,就会自增1,无论用还是不用
}
9 函数基础
// 函数基础
package main
import "fmt"
/*
注意:函数定义后可以不使用
1 定义函数基础语法:
func关键字 函数名(形参1 形参1类型,形参2 形参2类型)(返回值类型){
函数体内容(与缩进无关、括号内都是函数体内容)
}
*/
// 2 简单的函数定义、无参数无返回值
func test() {
fmt.Println("我是test")
}
// 3 定义有参数、无返回值函数、参数类型相同
func test2(x int,y int) {
fmt.Println(x)
}
// 4 定义有参数、无返回值、参数类型相同
func test3(a, b int, c,d string) {
fmt.Println(a,b,c,d)
}
// 5 定义有2参数、有1个返回值 -- return
func test4(a,b int) int {
c := a+b
return c
}
// 6 定义2个参数、2个返回值
func test5(a, b int) (int,int) {
c := a+b
d := a*b
return c,d
}
// 7 命名返回值,函数体不用重新定义
func test6(a, b int) (add int, mul int) {
add = a+b
mul = a*b
return // return可以直接省略add、mul
}
func main() {
// 在main调用函数
fmt.Println("s5开始执行了")
test()
test2(10, 20) // 只有位置传参、没有关键字传参、没有默认参数(有几个参数就传几个)
test3(10,20,"cx","ll")
// 接收1个返回值
var a = test4(5,6)
b := test4(1,2)
fmt.Println(a,b)
// 接收两个返回值
a2,b2 := test5(6,6)
fmt.Println(a2,b2)
// 有多个返回值只接收1个、如果用变量接收但不实用、会报错
// _接收,不使用也不会报错
a3,_:=test5(4,5)
fmt.Println(a3)
// 命名返回值的使用
add,mul := test6(1,2)
fmt.Println(add,mul)
}
10 函数高级
// 函数高级
package main
import "fmt"
// 注意:Go以包作为最小单位、所以函数名不能和同个包的函数重名
// 1 可变长参数
// 可接收任意长度int类型的参数
func test7(a ...int) {
fmt.Println(a) // 切片
}
// 2 匿名函数:在main里
/*
3 函数也是一种类型--是一等公民/头等函数 go、python是 Java不是
指:可以把函数当变量使用
4 函数是变量 就可以当参数传递、当返回值返回
5 闭包函数:必须符合两个条件:
1、定义在函数内部
2、对外部作用域有引用
go有闭包函数、可以做出装饰器来 但是没有语法糖语法
*/
func test8() func() {
name := "cx"
a:=func(){
fmt.Println("内层函数")
fmt.Println(name)
}
return a
}
// 6 尽量要看懂:函数是变量 就可以当参数传递、当返回值返回
// 函数是一种类型、函数的参数和返回值都是类型的一部分
func test9(aa int) func(a int,b func())(int,func()){
return func(a int,b func())(int,func()) {
fmt.Println("我是内层函数")
return a, func() {}
}
}
// 7 给类型重命名
type MyFunc func(a int,b func())(int,func())
func test10() MyFunc {
return func(a int,b func())(int,func()) {
fmt.Println("我是内层函数")
return a, func() {}
}
}
func main() {
// 与python
test7(1,2,3,4,5)
// 2 定义在函数内部的函数,必须是匿名函数
// 2.1 无参数
func (){
fmt.Println("我是匿名函数")
}() // 要执行否则报错
// 2.2 有参数
func (a,b int){
fmt.Println("我是匿名函数")
}(1,2)
// 2.3 有参数 有返回值
var a,b = func (a,b int)(int,int){
fmt.Println("我是匿名函数")
return a,b
}(1,2)
fmt.Println(a,b)
// 3 函数是一等公民 --> 可以把函数赋值给一个变量
var f = func (){
fmt.Println("我是匿名函数")
}
fmt.Println(f) // 内存地址
f() // 调用
fmt.Printf("type:%T", f)
// 4、5闭包
var f2 func()=test8()
f2()
// 调用test9
// 方式一:
var f3 func(a int,b func())(int,func()) = test9(11)
f3(1,f2)
// 方式二:
var f4=test9(11)
f4(1,f2)
// 方式三:
f5:=test9(11) // 简略声明会方便很多、最常用
f5(1,f2)
}