01. 关于 Go
编译型语言(性能高),Go 语言 => 编辑器 => 可执行文件 => 操作系统 + CPU 执行。
解释型语言(跨平台好)。
02. 下载 Go
下载 Go,直接下一步安装。
D:\Soft\Go\bin\go.exe 编译器。
# 查看和 Go 相关的环境变量的情况
go env
# 比较关键的有下面几个
# GO111MODULE=on
# GOROOT=D:\Soft\Go
# GOPATH=C:\Users\dangp\go
# GOPROXY=https://goproxy.cn,direct
如何关闭 GOMOD?
go env -w "GO111MODULE=off"
# 配置环境变量,默认安装后是有的
GOPATH C:\Users\dangp\go
# 下面的三个文件
# src,存放源代码(手动创建)
# pkg,存储编译后生成的包文件,例如第三方包
# bin,可执行文件
# 查看安装的 Go 版本
go version
# go version go1.23.4 windows/amd64
03. 第一个 Go 程序
package main
// 会去 GOROOT/src 下面查找 fmt
import "fmt"
func main() {
fmt.Println("Hello World")
}
go build # 会自动找到 main 包,生成一个可执行的二进制文件
go build -o 包名
# 可以将编译和执行二合一
go run test.go
04. 下载 GoLand
www.jetbrains.com.cn/go/download…
main.go
package main
import "fmt"
func main() {
fmt.Println("Hello World")
}
创建项目时,保证 GOROOT 的位置正确。
如何运行 Go 文件?
# go build # 会找 main 包进行构建
# go build -o 可执行文件.exe
go run main.go
05. 变量和常量
5.1 如何定义变量
变量是对具体值的引用。
- 先声明再赋值。
var name string
name = "危险"
fmt.Println(x)
- 声明和赋值一起。
var name string = "危险"
// 声明和赋值一起的时候,也可以省略类型
var name = "危险"
- 变量的默认值是类型的默认值。
var age int
// 默认是类型的默认值
fmt.Println(age) // 0
- 可以一次性声明多个变量。
var (
name string
address string
)
name = "危险"
address = "河南"
fmt.Println(name, address)
var a, b, c = 1, 2, 3
fmt.Println(a, b, c)
5. 短变量(推荐)。
// 可以省略 var 和数据类型
name := "危险"
age := 18
fmt.Println(name, age)
5.2 如何交换变量
// 注意点:a 和 b 的类型要保持一致
a := 4
b := 7
a, b = b, a
fmt.Println(a, b) // 7 4
5.3. 如何打印内存地址?
| 运算符 | 描述 | 实例 |
|---|---|---|
| & | 返回变量存储地址 | 例如 &a,将给出变量的实际地址 |
| * | 指针变量。 | 例如 *a,表示一个指针变量 |
package main
import "fmt"
func main() {
name := "危险"
// %d 是数字 => decimal
// %s 是字符串
// 注意这儿用的是 Printf,不是 Println
fmt.Printf("name 的值是:%s,内存地址是:%p", name, &name)
}
5.4 什么是匿名变量
var _, b = 1, 2
fmt.Println(b) // 2
package main
import "fmt"
func test() (int, int) {
return 10, 20
}
func main() {
// 匿名变量
a, _ := test()
fmt.Println(a) // 10
}
5.5 如何定义常量
package main
func main() {
// 定义常量推荐大写
// 1. 常量定义了可以不使用
// 2. 常量不能使用 := 简写
// 3. 常量和变量放置的内存地址不同,常量是放在常量池中的,正常是取不到地址的
// 4. 常量也可以如下方式定义多个
const URL, API string = "wps.cn", "https://www.google.com"
}
5.6 iota(了解)
package main
import "fmt"
// iota 常量计数器(一组中的),默认是 0,每定义一个常量 iota 的值就会 +1
func main() {
const (
a = iota
b = iota
c = iota
d = 0
e = iota
// 如果在定义 const 的时候,如果下面的常量没有赋值,默认沿用上面一个常量定义的赋值,例如下面的 f,g 就是 iota
f
g
h
// ... 1000+
)
const (
i = iota
j = 8 // iota + 1
k = iota // iota + 1 = 2
)
fmt.Println(a, b, c, d, e, f, g, h) // 0 1 2 0 4 5 6 7
fmt.Println(i, j, k) // 0 8 2
}
5.7 关于全局和局部变量
package main
import "fmt"
// 全局变量
// 1. 定义在 Go 文件的非函数内
// 2. 全局变量必须使用 var 关键字
// 3. 全局变量定义了可以不使用
var c int
func main() {
// 局部变量
a := 1
b := 2
c = a + b
// 如果全局变量有,用的是全局的
fmt.Printf("c的地址是: %p", &c) // 0xbbc570
// 如果局部变量有,用的是局部的
c := a + b
fmt.Printf("c的地址是: %p", &c) // 0xc00000a0f8
c = 8
// 就近原则
fmt.Printf("c的地址是: %p", &c) // 0xc00000a0f8
fmt.Println(c)
}
06. 基本数据类型
位(bit):计算机中数据储存的最小单位,字节(Byte):计算机中数据存储的单位。
1 Byte = 8 bit
6.1 整型
| 类型 | 取值范围 |
|---|---|
| int8 | -128到127 |
| uint8 | 0 到 255 |
| int16 | -32768 到 32767 |
| uint16 | 0 到 65535 |
| int32 | -2147483648 到 2147483647 |
| uint32 | 0 到 4294967295 |
| int64 | -9223372036854775808 到 9223372036854775807 |
| uint64 | 0 到 18446744073709551615 |
| uint | 与平台相关,32 位操作系统上就是 uint32,64 位操作系统上就是 uint64 |
| int | 与平台相关,32 位操作系统上就是 int32,64 位操作系统上就是 int64 |
如何计算?
uint32 => 0 ~ Math.pow(2, 32) - 1
int32 => -Math.pow(2, 31) ~ Math.pow(2, 31) - 1
越界报错演示?
var x int
x = 9223372036854775808
fmt.Print(x) // overflows int
// cannot use 9223372036854775808 (untyped int constant) as int value in assignment (overflows)
如何进行进制转换?
var a int = 10
fmt.Printf("%d \n", a) // 10 占位符%d表示十进制
fmt.Printf("%b \n", a) // 1010 占位符%b表示二进制
fmt.Printf("%o \n", a) // 12 占位符%o表示八进制
fmt.Printf("%x \n", a) // a 占位符%x表示十六进制
// 0 开始的表示八进制,例如 020,0x 开始的表示十六进制,例如 ox12
如何查看类型?
package main
import (
"fmt"
"reflect"
)
func main() {
var x = 1
fmt.Println(reflect.TypeOf(x)) // int
}
6.2 特殊的类型 bite 和 rune
package main
import "fmt"
func main() {
// uint8 的别名是 byte,十分常用
// 常用来表示 0 ~ 255 之间的整数
var num1 byte = 255
fmt.Printf("%T\n", num1)
// int32 的别名是 rune
var num2 rune = 1000000000
fmt.Printf("%T\n", num2)
}
6.3 浮点型
浮点型有两种,float32 和 float64,默认为 float64(可保留的小数点位数更多)
var f3 = 1.47
fmt.Println(f3, reflect.TypeOf(f3)) // 默认 float64
//3 乘以 10 的 -2 次方
var x = 3e-2
var y = 4e2
fmt.Println(x, y) // 0.03, 400
6.4 布尔
var b1 = true
fmt.Println(reflect.TypeOf(b1)) // bool
6.5 字符串
6.5.1 基本操作
var str = "hello world"
// 1. 索引取值
s1 := str[1]
fmt.Println(s1) // 101
fmt.Println(string(s1)) // e
// 2. 通过切片的形式取值
s2 := str[2:5]
fmt.Println(s2) // llo
fmt.Println(reflect.TypeOf(s2)) // string
// 3. 字符串拼接
s3 := str + " 123"
fmt.Println(s3) // hello world 123
6.5.2 转义符
var str = "hello world "🤠""
fmt.Println(str) // hello world "🤠"
6.5.3 多行字符串
通过 `` 包裹的能严格保留内部的格式。
var str = `
1. a
2. b
`
fmt.Println(str)
6.5.4 常用方法
| 方法 | 介绍 |
|---|---|
len(str) | 求长度 |
strings.ToUpper,strings.ToLower | 生成一个新的全部大写的字符串,生成一个新的全部小写的字符串 |
strings.ReplaceAll | 生成一个新的原字符串被指定替换后的字符串 |
strings.Contains | 判断是否包含 |
strings.HasPrefix,strings.HasSuffix | 前缀/后缀判断 |
strings.Trim | 去除字符串两端匹配的内容 |
strings.Index(),strings.LastIndex() | 子串出现的位置 |
strings.Split | 分割,将字符串按指定的内容分割成数组 |
strings.Join(a[]string, sep string) | join操作,将数组按指定的内容拼接成字符串 |
07. 类型转换
Go 语言不存在隐式类型转换,所有的类型转换都必须显式的声明:A = A(B)
新类型的值 = 新类型(旧类型的值)
package main
import "fmt"
func main() {
// 浮点数转整数,会截断,只保留整数部分
a := 5.9 // float
b := int(a) // b 就是 int 类型的 5
fmt.Printf("%T,%.1f\n", a, a) // float64, 5.9
fmt.Printf("%T,%d\n", b, b) // int, 5
// 整数转浮点数
c := 1
d := float64(c)
fmt.Printf("%T,%d\n", c, c) // int, 1
fmt.Printf("%T,%f\n", d, d) // float64, 1.000000
// 布尔类型转换,布尔类型是不支持转换为 int
// var flag bool = true
// f := int(flag)
}
// 1. 整形之间转换
var a int8 = 20
// int8 转 int64
fmt.Println(int64(a), reflect.TypeOf(int64(a))) // 20, int64
// int8 转 float64
fmt.Println(float64(a), reflect.TypeOf(float64(a))) // 20, float64
// 2. string 与 int 类型的转换
// int 转 string
x := strconv.Itoa(98)
fmt.Println(x, reflect.TypeOf(x)) // 98, string
// string 转 int
y, _ := strconv.Atoi("98")
fmt.Println(y, reflect.TypeOf(y)) // 98, int
// 3. Parse
// 把数字型的字符串转成 int
// 参数1:数字型的字符串
// 参数2:数字型字符串的进制
// 参数3:如果字符串转换的结果超过了 bitSize 的最大值,那么则输出 intBitSize 的最大值
x1, _ := strconv.ParseInt("1000", 10, 8)
fmt.Println(x1) // 127
x2, _ := strconv.ParseInt("1000", 10, 64)
fmt.Println(x2) // 1000
// 把浮点型的字符串转换成 Float
x3, _ := strconv.ParseFloat("1.211", 64)
fmt.Println(x3, reflect.TypeOf(x3)) // 1.211, float64
// 把布尔型的字符串转换成 Boolean
b1, _ := strconv.ParseBool("true")
fmt.Println(b1, reflect.TypeOf(b1)) // true, bool
08. 关于分支
fmt.Scan($num1),接受输入,注意参数要是一个地址。
package main
import "fmt"
// 需求:两次输入 123456,提示登录成功
func main() {
var num1 int
var num2 int
// 提示用户输入
fmt.Printf("请输入密码 : \n")
// &num1 地址
fmt.Scan(&num1)
if num1 == 123456 {
fmt.Println("请再次输入密码: ")
fmt.Scan(&num2)
if num2 == 123456 {
fmt.Println("登录成功!")
} else {
fmt.Println("登录失败!")
}
} else {
fmt.Println("登录失败")
}
}
switch 比 if else 更简洁,效率更高!
var choice int
fmt.Println("Choose a number:")
fmt.Scanln(&choice)
switch choice {
case 1:
fmt.Println("牛")
case 2:
fmt.Println("牛牛")
case 3:
fmt.Println("牛牛牛")
case 4:
fmt.Println("牛牛牛牛")
default:
fmt.Println("输入有误")
}
package main
import "fmt"
func main() {
a := false
// 这里的爆红不影响
switch a {
case false:
fmt.Println("1")
fallthrough // 在 case 中一旦使用了 fallthrough,则会强制执行下一个 case 语句
case true:
fmt.Println("2")
case false:
fmt.Println("3")
default:
fmt.Println("6")
}
}
09. 关于循环
求 1 ~ 100 的和。
var s = 0
for i := 1; i <= 100; i++ {
s += i
}
fmt.Println(s) // 5050
无限循环。
for true {
var choice int
fmt.Println("Choose a number:")
fmt.Scanln(&choice)
switch choice {
case 1:
fmt.Println("牛")
case 2:
fmt.Println("牛牛")
case 3:
fmt.Println("牛牛牛")
case 4:
fmt.Println("牛牛牛牛")
default:
fmt.Println("输入有误")
}
}
打印一个十行十列的矩形。
for i := 0; i < 10; i++ {
for j := 0; j < 10; j++ {
fmt.Print(" * ")
}
fmt.Print("\n")
}
直接三角形。
*
* *
* * *
* * * *
* * * * *
* * * * * *
* * * * * * *
* * * * * * * *
* * * * * * * * *
for i := 0; i < 10; i++ {
for j := 0; j < i; j++ {
fmt.Print(" * ")
}
//fmt.Print("\n")
fmt.Println()
}
10. 输出输出
10.1 输出函数
- fmt.Print(),不换行输出
- fmt.Println(),换行输出
- fmt.printf(),格式化输出
name := "John Doe"
age := 18
isMarried := false
salary := 123.4
fmt.Printf("姓名:%s 年龄:%d 婚否:%t 薪资:%.2f\n", name, age, isMarried, salary)
fmt.Printf("姓名:%v 年龄:%v 婚否:%v 薪资:%v\n", name, age, isMarried, salary)
- fmt.Sprintf(),不会输出到终端,而是返回加工后的字符串
// ...
info := fmt.Sprintf("姓名:%s 年龄:%d 婚否:%t 薪资:%.2f\n", name, age, isMarried, salary)
fmt.Println(info) // 姓名:John Doe 年龄:18 婚否:false 薪资:123.40
10.2 输入函数
- fmt.Scan()
输入求和。
var a, b int
fmt.Print("请输入第一个数字:")
fmt.Scan(&a)
fmt.Print("请输入第一个数字:")
fmt.Scan(&b)
fmt.Println("合计:", a+b)
- fmt.Scanf(),输入多个时,可以以指定的形式隔开
var a, b int
fmt.Scan(&a, &b) // 输入:1 2
//fmt.Scanf("%d + %d", &a, &b) // 输出:1 + 2
fmt.Println(a + b)
- fmt.Scanln()
了解 Scan 和 Scanln 的区别,如果是 Scan,先输入 1,再敲回车,会继续等待,可以再输入 2,而 Scanln 是遇到回车就结束啦。
package main
import "fmt"
func main() {
var a, b int
fmt.Print("请输入两个整数,用空格分隔,然后按回车键: ")
fmt.Scanln(&a, &b)
fmt.Printf("你输入的两个整数是: %d 和 %d\n", a, b)
}