P3 Go语言环境安装
- GOROOT:go的安装目录(例:D:\Environment\Go);
- GOPATH:go的工作目录,存放代码的地方(例:D:\Apps\GoWorks);
- 在工作目录下新建三个文件夹:bin、pkg、src,用于存放之后开发的代码;
- 常用命令:
go version #查看go版本信息
go env #查看go环境配置信息
go env -w GO111MODULE=off #-w设置env的某个值
P5 HelloWorld
- fmt.Println输出时,需要用双引号,不然程序会报错!
- GO语言编译的程序都必须有且只能有一个main包(package)和main(func)方法。
package main // 必须有import "fmt"func main() { // 必须有//打印一句话,打印完后换行fmt.Printf("Hello World")
}
P9 什么是变量
- 强类型语言,声明数据类型之后不可以更改(PHP低版本可随意更改);
- var声明变量,可以声明多个变量,声明的变量一定要使用,不使用会报错;
P10 变量初始化
:=
P11 打印内存地址
%p&变量名
var num int
num = 100
fmt.Printf("num:%d, 内存地址:%p", num, &num) //取地址符 &变量名
//输出:num:100, 内存地址:0xc0000160b8
P12 变量交换
package mainimport "fmt"func main() {var (a int = 1b int = 2)//变量交换a, b = b, afmt.Println(a, b) //输出 2, 1
}
P13 匿名变量_
_
package mainimport "fmt"func test() (int, int) {return 100, 200
}func main() {// 对象:Usera, _ := test()_, b := test()fmt.Println(a, b) //输出:100, 200
}
P14 变量的作用域
- 全局变量:定义在main函数外面,没有其它函数包裹的变量;
- 函数内部变量(局部变量)可以和全局变量重名,局部变量优先级高于全局变量;
P15 常量
- 常量是一个简单地标识符,在程序运行时,不会被修改的量;
- 常量字符类型只能是:布尔型、数字型、字符串型;
package mainimport "fmt"func main() {const URL string = "www.baidu.com" //显示定义const URL2 = "www.baidu.com" //隐式定义,默认推导数据类型,此处不用加`:`const a, b, c = 3.14, "ks", false//URL = "wwww" //此处改变变量值会报错:cannot assign to URLfmt.Println(URL, URL2)fmt.Println(a, b, c)
}
P16 常量iota
iota
package mainimport "fmt"func main() {const (a = iotabcd = 100ef = "zs"g // 沿用上一个常量的值h = iotai)//在const关键字出现时将被重置为0const (j = iotak)fmt.Println(a, b, c, d, e, f, g, h, i, j, k) //输出:0 1 2 100 100 zs zs 7 8 0 1
}
P17 布尔类型
- Go 语言是一种静态类型的编程语言;
- 输出的时候,%T(type):数据类型,%t:(布尔类型)数据的值
package mainimport "fmt"func main() {// var 变量名 数据类型//bool默认值为falsevar isFlag bool = falsevar isFlag2 bool = true//%T type:数据类型//%t:数据的值fmt.Printf("%T, %t\n", isFlag, isFlag)fmt.Printf("%T, %t\n", isFlag2, isFlag2)
}
P18 数字类型
float32
package mainimport "fmt"func main() {//定义一个整型,%d:(int类型)数据的值//byte uint8 0-255,不能有负数、且最大值255//rune int32//int int64var age int = 18fmt.Printf("%T, %d\n", age, age)//定义一个浮点型,%f:(float类型)数据的值var money float32 = 3.1415fmt.Printf("%T, %f\n", money, money)//默认是6位小数打印,3.141500,%.2f:数字表示精度(四舍五入)fmt.Printf("%T, %.2f\n", money, money) //输出:float32, 3.14var (num1 float32 = -123.0000901 //输出:-123.00009,少了一个精度num2 float64 = -123.0000901num3 float32 = -1.0000901 //输出:-1.0000901,可以完全输出)//尽量使用 float64 定义float数据,不然精度容易丢失fmt.Println(num1, num2, num3)
}
P19 字符与字符串
package mainimport "fmt"func main() {var str stringstr = "Hello!"fmt.Printf("%T, %s\n", str, str)//单引号 字母,整型-ASCII字符码//扩展://所有的中国字的编码表:GBK//全世界的编码变:Unicode编码表v1 := '中'v2 := "A"fmt.Printf("%T, %d\n", v1, v1) //输出:int32, 65fmt.Printf("%T, %s\n", v2, v2)//字符串链接 +fmt.Println("Hello" + ", World!")//转义字符 \fmt.Println("Hello\"World!")fmt.Println("Hello\nWorld!") // n 换行fmt.Println("Hello\tWorld!") // t 制表符
}
P20 数据类型的转换
- 由于Go语言不存在隐式类型转换,因此所有的类型转换都必须是显式的声明;
- 转换后的变量 := 要转换的类型(变量), 备注:整型是不能转化为bool类型的;
package mainimport "fmt"// 类型转换
// 转换后的变量 := 要转换的类型(变量)
// 备注:整型是不能转化为bool类型的
func main() {a := 3 //intb := 5.0 //float64//需求:将int类型的a转换位 float64 类型 类型转换c := float64(a)d := int(b)// bool 整型是不能转化为bool类型的//e := bool(a)fmt.Printf("%T\n", a)fmt.Printf("%T\n", b)fmt.Printf("%T\n", c)fmt.Printf("%T\n", d)
}
P24 位运算符
&&&
package mainimport "fmt"func main() {// 二进制 0 1 逢二进一// 位运算:二进制上的 0 false, 1 true// & 我和你 1 1 结果才为1, 0 1为 0// | 我或者你 0 1 为1, 0 0 为 0// 60 0011 1100// 13 0000 1101// ------------// & 0000 1100 4+8=12// | 0011 1101 1+4+8+16+32=61// ^ 0011 0001 不同为1,相同为0a := 60b := 13//位运算c := 0//%b(binary),二进制形式输出c = a & b //位运算符fmt.Printf("%d,二进制:%b \n", c, c) //输出:12,二进制:1100c = a | b //位运算符fmt.Printf("%d,二进制:%b \n", c, c) //输出:61,二进制:111101c = a >> 2 //位运算符fmt.Printf("%d,二进制:%b \n", c, c) //输出:15,二进制:1111c = a << 2 //位运算符fmt.Printf("%d,二进制:%b \n", c, c) //输出:240,二进制:11110000
}
P26 拓展之获取键盘输入
package mainimport "fmt"func main() {var x intvar y float64//定义两个变量,用键盘来录入这两个变量//fmt.Printf() // 格式化输出//fmt.Println() // 打印并换行//fmt.Print() // 打印输出fmt.Println("请输入两个数: 1、正数, 2、浮点数:")// 变量取地址 &变量// Scanln 阻塞等待你的键盘输入fmt.Scanln(&x, &y)fmt.Println("x:", x)fmt.Println("y:", y)//fmt.Scanf() //接收输入 格式化输入//fmt.Scanln() //接收输入 Scan |//fmt.Scan() //接收输入
}
P27 小结聊聊编码规范
- 引入包顺序:
- 标准库包
- 程序内部包
- 第三方包
P29 if语句
package mainimport "fmt"// if 如果。。。否则 else
func main() {// 分数var score int = 90// a b c dif score >= 90 && score <= 100 {fmt.Println("A")} else if score >= 80 && score < 90 {fmt.Println("B")} else if score >= 70 && score < 80 {fmt.Println("C")} else if score >= 60 && score < 70 {fmt.Println("D")} else {fmt.Println("不及格")}
}
P30 if 多重嵌套
package mainimport "fmt"// if 嵌套语句
func main() {// 验证密码, 再次输入密码var a, b intvar pwd int = 20221020// 用户的输入fmt.Print("请输入密码:")fmt.Scanln(&a)if a == pwd {fmt.Print("请再次输入密码:")fmt.Scanln(&b)if b == pwd {fmt.Println("登录成功!")} else {fmt.Println("第二次密码错误")}} else {fmt.Println("密码错误")}
}
P31 switch语句
package mainimport "fmt"// switch语句
func main() {score := 90//匹配 caseswitch score {case 90:fmt.Println("A")fallthrough //穿透,继续往下执行 一个 casecase 80:fmt.Println("B")case 50, 60, 70:fmt.Println("C")default:fmt.Println("D")break // 跳出}// 输出:A B// switch 后面不跟,默认条件 bool = trueswitch {case false:fmt.Println("false")breakcase true:fmt.Println("true")default:fmt.Println("Other")}// 输出:true
}
P35 打印99乘法表
package mainimport ("fmt"
)// 目标:使用for循环打印99乘法表
func main() {for j := 1; j <= 9; j++ {for i := 1; i <= j; i++ {fmt.Printf("%d*%d=%d\t", i, j, i*j)}fmt.Println()}
}
P39 函数的声明和调用
// 函数的声明和调用
package mainimport "fmt"func main() {// 函数的调用printInfo()myPrint("haha!")myPrintNum(add2(1, 23))a, _ := swap("www", "com")fmt.Println(a)
}// 无参无返回值函数
func printInfo() {fmt.Println("printInfo")
}// 有一个参数的函数
func myPrint(msg string) {fmt.Println(msg)
}
func myPrintNum(num int) {fmt.Println(num)
}// 有两个参数的函数
// 有一个返回值的函数
func add2(a, b int) int {c := a + breturn c
}// 有多个返回值的函数
func swap(a, b string) (string, string) {return b, a
}
P41 可变参数
- 可变参数需要放到最后;
- 一个函数的参数列表中最多只能有一个可变参数;
// 可变参数
package mainimport "fmt"func main() {getSum(1, 2, 3, 4)
}// ...可变参数
func getSum(nums ...int) {sum := 0for i := 0; i < len(nums); i++ {fmt.Println(nums[i])sum += nums[i]}fmt.Println("sum:", sum)
}
P42 引用传递
- 值类型的传递(操作的是数据本身):
int、string、bool、float64、array… - 引用类型的数据(操作的是数据的地址):
slice(切片:可以扩容的数组)、map、channel…
package mainimport "fmt"// 引用传递
func main() {// 切片,可以扩容的数组s1 := []int{1, 2, 3}fmt.Println("默认的数据:", s1)// 传入的是引用类型的数据,地址update2(s1)fmt.Println("调用后的数据:", s1)
}func update2(s2 []int) {fmt.Println("传递的数据:", s2)s2[0] = 100fmt.Println("修改后的数据:", s2)
}
输出:
默认的数据: [1 2 3]
传递的数据: [1 2 3]
修改后的数据: [100 2 3]
调用后的数据: [100 2 3]
P46 defer延迟函数执行
- 函数执行到最后时,这些 defer 语句会按照逆序执行(类似栈结构)
package mainimport "fmt"// defer 延迟函数
func main() {a := 10fmt.Println("a=", a)defer f(a) // 参数已经传递进去了,在最后执行a++fmt.Println("end a=", a)defer f(a) // 比上面那个defer先执行
}func f(s int) {fmt.Println("函数里面的a=", s)
}
输出:
a= 10
end a= 11
函数里面的a= 11
函数里面的a= 10
P47 函数本质的探讨
- 函数加括号是调用,不加括号是变量
package mainimport "fmt"// 函数本质的探讨
// func() 本身就是一个数据类型
func main() {// f3 如果不加括号,函数就是一个变量// f3() 如果加了括号那就成了函数的调用fmt.Printf("%T\n", f3) // func()| func(int, int) | func(int, int) int//fmt.Printf("%T\n", 10) // int//fmt.Printf("%T\n", "hello") // string// 定义函数类型的变量var f4 func(int, int)f4 = f3 // 引用类型的fmt.Println(f4)fmt.Println(f3)f4(1, 2)
}func f3(a, b int) {fmt.Println(a, b)
}
P48 匿名函数推导
- 将匿名函数作为另一个函数的参数,回调函数
- 将匿名函数作为另外一个函数的返回值,可以形成闭包结构
package mainimport "fmt"// 匿名函数的推导
func main() {f5()f6 := f5 // 函数本身也是一个变量f6()// 匿名函数f7 := func() {fmt.Println("我是f7函数")}f7()// 匿名函数自己调用自己func(a, b int) {fmt.Println(a, b)fmt.Println("我是f8函数")}(1, 2)// 匿名函数自己调用自己res := func(a, b int) int {return a + b}(1, 2)fmt.Println(res)
}func f5() {fmt.Println("我是f5函数")
}
P49 函数式编程
- 高阶函数: 将一个函数座位另外一个函数的参数
package mainimport "fmt"// 函数式编程
func main() {r1 := add3(1, 2)fmt.Println(r1)r2 := oper(3, 4, add3)fmt.Println(r2)r3 := oper(8, 4, sub)fmt.Println(r3)r4 := oper(8, 4, func(i int, i2 int) int {if i2 == 0 {fmt.Println("除数不能为0")return 0}return i / i2})fmt.Println(r4)
}// 高阶函数,可以接受一个函数作为参数
func oper(a, b int, fun func(int, int) int) int {res := fun(a, b)return res
}func add3(a, b int) int {return a + b
}func sub(a, b int) int {return a - b
}
P50 闭包结构的理解
- 闭包结构:
一个外层函数increment()中,有内层函数fun,该内层函数中,会操作外层函数的局部变量i,并且该外层函数increment()的返回值就是这个内层函数fun。这个内层函数fun和外层函数increment()的局部变量i,统称为闭包结构; - 局部变量的生命周期就会发生改变:
正常的局部变量会随着函数的调用而创建,随着函数的结束而销毁; - 闭包结构中的外层函数的局部变量i并不会随着外层函数increment()的结束而销毁,因为内层函数还在继续使用
package mainimport "fmt"// 闭包结构的理解
func main() {r1 := increment()fmt.Println(r1)v1 := r1()fmt.Println(v1)v2 := r1()fmt.Println(v2)fmt.Println(r1())fmt.Println(r1())fmt.Println(r1())r2 := increment()v3 := r2()fmt.Println(v3)fmt.Println(r1())fmt.Println(r2())
}// 自增
func increment() func() int {// 局部变量i := 0// 定义一个匿名函数,给变量自增并返回fun := func() int { // 内层函数,没有执行的// 局部变量的声明周期发生了变化i++return i}return fun
}
问题
- GOROOT和GOPATH的区别?
Loading… - 格式化输出哪些字母代表什么含义?
Go语言格式化输出,%(占位符)使用