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 main
import "fmt"
func main() {
var (
a int = 1
b int = 2
)
//变量交换
a, b = b, a
fmt.Println(a, b) //输出 2, 1
}
P13 匿名变量_
_
任何赋值给这个标识符的值都将被抛弃- 匿名变量不占用内存空间,不会分配内存
package main
import "fmt"
func test() (int, int) {
return 100, 200
}
func main() {
// 对象:User
a, _ := test()
_, b := test()
fmt.Println(a, b) //输出:100, 200
}
P14 变量的作用域
- 全局变量:定义在main函数外面,没有其它函数包裹的变量;
- 函数内部变量(局部变量)可以和全局变量重名,局部变量优先级高于全局变量;
P15 常量
- 常量是一个简单地标识符,在程序运行时,不会被修改的量;
- 常量字符类型只能是:布尔型、数字型、字符串型;
package main
import "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 URL
fmt.Println(URL, URL2)
fmt.Println(a, b, c)
}
P16 常量iota
iota
特殊常量,在const关键字出现时将被重置为0;- 可以叫做:常量计数器;
package main
import "fmt"
func main() {
const (
a = iota
b
c
d = 100
e
f = "zs"
g // 沿用上一个常量的值
h = iota
i
)
//在const关键字出现时将被重置为0
const (
j = iota
k
)
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 main
import "fmt"
func main() {
// var 变量名 数据类型
//bool默认值为false
var isFlag bool = false
var isFlag2 bool = true
//%T type:数据类型
//%t:数据的值
fmt.Printf("%T, %t\n", isFlag, isFlag)
fmt.Printf("%T, %t\n", isFlag2, isFlag2)
}
P18 数字类型
- 输出的时候:
- %d:(int类型)数据的值;
- %f:(float类型)数据的值;
float32
默认是6位小数打印,%.2f:数字表示精度(四舍五入);- 尽量使用 float64 定义float数据,不然精度容易丢失;
package main
import "fmt"
func main() {
//定义一个整型,%d:(int类型)数据的值
//byte uint8 0-255,不能有负数、且最大值255
//rune int32
//int int64
var age int = 18
fmt.Printf("%T, %d\n", age, age)
//定义一个浮点型,%f:(float类型)数据的值
var money float32 = 3.1415
fmt.Printf("%T, %f\n", money, money)
//默认是6位小数打印,3.141500,%.2f:数字表示精度(四舍五入)
fmt.Printf("%T, %.2f\n", money, money) //输出:float32, 3.14
var (
num1 float32 = -123.0000901 //输出:-123.00009,少了一个精度
num2 float64 = -123.0000901
num3 float32 = -1.0000901 //输出:-1.0000901,可以完全输出
)
//尽量使用 float64 定义float数据,不然精度容易丢失
fmt.Println(num1, num2, num3)
}
P19 字符与字符串
package main
import "fmt"
func main() {
var str string
str = "Hello!"
fmt.Printf("%T, %s\n", str, str)
//单引号 字母,整型-ASCII字符码
//扩展:
//所有的中国字的编码表:GBK
//全世界的编码变:Unicode编码表
v1 := '中'
v2 := "A"
fmt.Printf("%T, %d\n", v1, v1) //输出:int32, 65
fmt.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 main
import "fmt"
// 类型转换
// 转换后的变量 := 要转换的类型(变量)
// 备注:整型是不能转化为bool类型的
func main() {
a := 3 //int
b := 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 位运算符
&&
操作两个bool类型变量,&
操作二进制值;- %b(binary):二进制形式输出;
package main
import "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,相同为0
a := 60
b := 13
//位运算
c := 0
//%b(binary),二进制形式输出
c = a & b //位运算符
fmt.Printf("%d,二进制:%b \n", c, c) //输出:12,二进制:1100
c = a | b //位运算符
fmt.Printf("%d,二进制:%b \n", c, c) //输出:61,二进制:111101
c = a >> 2 //位运算符
fmt.Printf("%d,二进制:%b \n", c, c) //输出:15,二进制:1111
c = a << 2 //位运算符
fmt.Printf("%d,二进制:%b \n", c, c) //输出:240,二进制:11110000
}
P26 拓展之获取键盘输入
package main
import "fmt"
func main() {
var x int
var 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 main
import "fmt"
// if 如果。。。否则 else
func main() {
// 分数
var score int = 90
// a b c d
if 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 main
import "fmt"
// if 嵌套语句
func main() {
// 验证密码, 再次输入密码
var a, b int
var 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 main
import "fmt"
// switch语句
func main() {
score := 90
//匹配 case
switch score {
case 90:
fmt.Println("A")
fallthrough //穿透,继续往下执行 一个 case
case 80:
fmt.Println("B")
case 50, 60, 70:
fmt.Println("C")
default:
fmt.Println("D")
break // 跳出
}
// 输出:A B
// switch 后面不跟,默认条件 bool = true
switch {
case false:
fmt.Println("false")
break
case true:
fmt.Println("true")
default:
fmt.Println("Other")
}
// 输出:true
}
P35 打印99乘法表
package main
import (
"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 main
import "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 + b
return c
}
// 有多个返回值的函数
func swap(a, b string) (string, string) {
return b, a
}
P41 可变参数
- 可变参数需要放到最后;
- 一个函数的参数列表中最多只能有一个可变参数;
// 可变参数
package main
import "fmt"
func main() {
getSum(1, 2, 3, 4)
}
// ...可变参数
func getSum(nums ...int) {
sum := 0
for 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 main
import "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] = 100
fmt.Println("修改后的数据:", s2)
}
输出:
默认的数据: [1 2 3]
传递的数据: [1 2 3]
修改后的数据: [100 2 3]
调用后的数据: [100 2 3]
P46 defer延迟函数执行
- 函数执行到最后时,这些 defer 语句会按照逆序执行(类似栈结构)
package main
import "fmt"
// defer 延迟函数
func main() {
a := 10
fmt.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 main
import "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 main
import "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 main
import "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 main
import "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的区别?
(一)GOROOT,GOPATH,GOMOD解析、Windows上Go环境配置、常用命令记录 - 格式化输出哪些字母代表什么含义?
Go语言格式化输出,%(占位符)使用