使用总结
1.go自动识别变量类型
输入:
name := "xx"
fmt.Println(name)
输出:
xx
2.Printf使用
(1)输入:
func main() {
name := "xx"
age := 10
fmt.Println(name, age)
//Printf 按照指定格式输出
fmt.Printf("%T,%T", name, age)
}
输出:
xx 10
string,int
(2)输入:
func main() {
age := 10
//& 取地址符
fmt.Printf("数字为:%d,地址为:%p", age, &age)
}
输出:
数字为:10,地址为:0xc000112068
(3)输入:
func main() {
age := 10
fmt.Printf("数字为:%d,地址为:%p", age, &age)
//变量内容发生变化,内存地址不变
age = 18
fmt.Println()
fmt.Printf("数字为:%d,地址为:%p", age, &age)
}
输出:
数字为:10,地址为:0xc00000a0a8
数字为:18,地址为:0xc00000a0a8
转载https://www.cnblogs.com/thsrite/p/11765201.html
3.变量值交换
(1)输入
func main() {
var a int = 1
var b int = 2
fmt.Println(a, b)
//GO实现数值交换
a, b = b, a
fmt.Println(a, b)
}
输出
1 2
2 1
4.匿名变量
(1)Go函数使用
输入:
// Go中函数的定义
func test() (int, int) {
return 100, 200
}
func main() {
//函数调用
a, b := test()
fmt.Println(a, b)
}
输出:
100 200
(2)匿名变量
好处:不占用内存空间
输入:
func test() (int, int) {
return 100, 200
}
func main() {
//函数传过来两个值,只使用第一个值,第二个用‘下划线’ _ 进行匿名代替
a, _ := test()
fmt.Println(a)
}
输出:
100
5.全局变量与局部变量
定义全局变量,不能使用 name := “ckm” 这种便捷写法
在全局变量中进行变量定义后,依然可以在局部及进行变量定义
输入:
// 定义全局变量
var name = "cc"
func test() {
fmt.Println(name)
}
func main() {
test()
//name = "xx" //直接对全局变量那么进行赋值
var name = "XX" //对name进行重新定义不会报错
fmt.Println(name)
}
输出:
cc
XX
6.常量定义
(1)常量定义
输入:
func main() {
//显式定义
const name1 string = "cc"
//隐式定义
const name2 = "kk"
//定义多个常量
const num, addr, isTrue = 3.1415, "中国", true
fmt.Println(name1)
fmt.Println(name2)
fmt.Println(num, addr, isTrue)
}
输出:
cc
kk
3.1415 中国 true
(2)递增常量iota
在const关键字出现时,重置为0
常量计数器
func main() {
//iota
const (
a = iota
b
c
d = "hello"
e
f = 100
g
h = false
i
j = iota
k
)
const (
//重新定义,重新计数
m = iota
n
)
fmt.Println(a, b, c, d, e, f, g, h, i, j, k, m, n)
}
输出:
0 1 2 hello hello 100 100 false false 9 10 0 1
7.数据类型:布尔(bool)
默认值为false
输入:
func main() {
var isFlag, isTrue, isOK bool
isFlag = true
fmt.Printf("数据类型为:%T,isFlag:%t\n", isFlag, isFlag)
fmt.Printf("数据类型为:%T,isFlag:%t\n", isTrue, isTrue)
fmt.Printf("数据类型为:%T,isFlag:%t\n", isOK, isOK)
}
输出
数据类型为:bool,isFlag:true
数据类型为:bool,isFlag:false
数据类型为:bool,isFlag:false
8.数据类型 数字
int、float64类型值默认为0
输入:
func main() {
var num1 int = 100
var num2 float64 = 3.1415
fmt.Printf("数据类型为:%T,num1的值为:%d\n", num1, num1)
fmt.Printf("数据类型为:%T,num2的值为:%f\n", num2, num2)
fmt.Printf("数据类型为:%T,num2保留一位小数点:%.1f\n", num2, num2)
}
输出:
数据类型为:int,num1的值为:100
数据类型为:float64,num2的值为:3.141500
数据类型为:float64,num2保留一位小数点:3.1
int 等同于 int64
9.字符类型
输入:
func main() {
var name string
fmt.Printf("数据类型为:%T,name的值为:%s\n", name, name)
var str1 = 'A'
var str2 = "A"
//ascii码
fmt.Printf("数据类型为:%T,str1的值为:%d\n", str1, str1)
fmt.Printf("数据类型为:%T,str2的值为:%s\n", str2, str2)
}
输出:
数据类型为:string,name的值为:
数据类型为:int32,str1的值为:65
数据类型为:string,str2的值为:A
10.字符转换
Go语言不存在隐式类型转换,所有类型转换都必须是显式的
输入:
func main() {
a := 10
b := 10.1
c := float64(a)
d := int(b)
fmt.Printf("数据类型为:%T\n", a)
fmt.Printf("数据类型为:%T\n", b)
fmt.Printf("数据类型为:%T\n", c)
fmt.Printf("数据类型为:%T\n", d)
}
输出:
数据类型为:int
数据类型为:float64
数据类型为:float64
数据类型为:int
11.关系运算符
错误输入
func main() {
a := 10
//直接输出a++是会报错的
fmt.Println(a++)
}
输入:
func main() {
a := 10
a++
fmt.Println(a)
}
输出:
11
12.获取键盘输入
输入:
func main() {
name := "xx"
fmt.Println(name) //输出并换行
fmt.Printf("格式为:%T,值为%s", name, name) //格式化输出
fmt.Print(name) //输出
var x int
var y float64
fmt.Println("请输入两个数,第一个数为整数,第二个数为小数")
fmt.Scanln(&x, &y) //阻塞,等待键盘输入
//若输入的数据类型不正确,返回默认值
fmt.Println("x的值为", x)
fmt.Println("y的值为", y)
}
输出:
13.switch
输入:
func main() {
var score = 80
switch score {
case 90:
fmt.Println("A")
case 80, 70:
fmt.Println("B")
case 60:
fmt.Println("C")
default:
fmt.Println("不及格")
}
//switch 默认的条件为 bool = true
switch {
case true:
fmt.Println("switch 空 默认为true")
case false:
fmt.Println("switch 空 默认为false")
default:
fmt.Println("其他")
}
}
输出:
B
switch 空 默认为true
switch中提供fallthrough可以实现穿透(只穿透一层)
输入:
func main() {
//switch 默认的条件为 bool = true
switch {
case true:
fmt.Println("switch 空 默认为true")
fallthrough
case false:
fmt.Println("switch 空 默认为false")
default:
fmt.Println("其他")
}
}
输出:
switch 空 默认为true
switch 空 默认为false
使用break终止穿透
输入:
func main() {
//switch 默认的条件为 bool = true
switch {
case true:
fmt.Println("switch 空 默认为true")
fallthrough
case false:
if true {
break
}
fmt.Println("switch 空 默认为false")
default:
fmt.Println("其他")
}
}
输出:
switch 空 默认为true
14.字符串
(1)字符长度
utf-8里面中文是占3个字节的,所以你使用内置len函数获取中文字符串长度不一定正确
输入:
func main() {
var name = "我是笑xx"
fmt.Println(name)
fmt.Println("字符总长度为:", len(name))
fmt.Printf("第一个字符为:%c", name[0])
}
输出:
我是笑xx
字符总长度为: 11
第一个字符为:æ
(2)字符遍历
字母数字占一个字符,中文占3个字符
name[i]输出中文会乱码
输出v不会乱码
输入:
func main() {
var name = "aaa我是笑xx"
for i, v := range name {
fmt.Print(i)
fmt.Printf("%c", name[i])
fmt.Printf("%c\n", v)
}
}
输出:
0aa
1aa
2aa
3æ我
6æ是
9ç笑
12xx
13xx
15.函数
输入:
func main() {
fmt.Println(add(1, 1))
}
func add(a, b int) int {
return a + b
}
输出:
2
练习使用
输入:
/ 交换函数,并输出
func main() {
name1, name2 := swap("xx", "ck")
fmt.Println(name1, name2)
}
/*
*
交换函数
*/
func swap(a, b string) (string, string) {
return b, a
}
/*
*
输出函数
*/
func printInfo(info string) {
fmt.Println(info)
}
输出:
ck xx
16.数组与切片
(1)数组
输入:
// 数组(值传递)
func main() {
ary1 := [3]int{1, 2, 3}
//输出更改函数执行前的数组
fmt.Println(ary1)
//执行函数
update(ary1)
//输出变换后的函数
fmt.Println(ary1)
}
// 变更函数
func update(ary2 [3]int) {
//输出传递的数组(值传递)
fmt.Println(ary2)
//进行数组值变更
ary2[0] = 100
//输出ary2值变更后的数组
fmt.Println(ary2)
}
输出:
[1 2 3]
[1 2 3]
[100 2 3]
[1 2 3]
(2)二维数组
输入:
// 二维数组遍历
func main() {
arr := [2][3]int{{1, 2, 3}, {4, 5, 6}}
for k, v := range arr {
for key := range v {
fmt.Print(arr[k][key], "\t")
}
fmt.Println()
}
}
输出:
1 2 3
4 5 6
(3)切片
切片的创建方式:
①定义一个切片,该切片引用已经创建好的数组
arr1 := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}//定义数组
arr2 := arr1[1:3] //左闭右开,切片arr2为[2,3]
②通过make内置函数创建切片
内建函数make分配并初始化一个类型为切片、映射、或通道的对象。其第一个实参为类型,而非值。make的返回类型与其参数相同,而非指向它的指针。其具体结果取决于具体的类型:
- 切片:size指定了其长度。该切片的容量等于其长度。切片支持第二个整数实参可用来指定不同的容量;它必须不小于其长度,因此 make([]int, 0, 10) 会分配一个长度为0,容量为10的切片。
- 映射:初始分配的创建取决于size,但产生的映射长度为0。size可以省略,这种情况下就会分配一个小的起始大小。
- 通道:通道的缓存根据指定的缓存容量初始化。若 size为零或被省略,该信道即为无缓存的。
//定义一个类型为int,长度为4,容量为20的切片
//原理:make底层创建一个数组,不可见,不可操作
slice := make([]int, 4, 20)
③直接指定具体数组
slice := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
fmt.Println(slice)
输入:
func main() {
//arr1为数组,arr2为切片,arr3为切片
arr1 := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
arr2 := arr1[1:3] //左闭右开,切片arr2为[2,3]
arr3 := []int{1, 2, 3}
fmt.Println(arr1) //输出切片变化前数组的值
fmt.Println(cap(arr2)) //输出切片容量
update(arr2) //切片值发生变化
fmt.Println(arr1) //数组的值发生变化!!!
fmt.Println(arr2)
fmt.Println(arr3)
}
func update(arr []int) {
arr[0] = 0
}
输出:
[1 2 3 4 5 6 7 8 9 10]
9
[1 0 3 4 5 6 7 8 9 10]
[0 3]
[1 2 3]
输入:
// 切片(引用传递)
func main() {
ary1 := []int{1, 2, 3}
//输出更改函数执行前的切片
fmt.Println(ary1)
//执行函数
update(ary1)
//输出变换后的切片
fmt.Println(ary1)
}
// 变更函数
func update(ary2 []int) {
//输出传递的切片(引用传递,同一个地址)
fmt.Println(ary2)
//进行切片值变更
ary2[0] = 100
//输出ary2值变更后的切片
fmt.Println(ary2)
}
输出:
[1 2 3]
[1 2 3]
[100 2 3]
[100 2 3]
PS:
切片简写方式:
对数组进行切片时,从0开始时可以省略,结束为数组的长度时也可以省略
支持对切片继续切片
输入:
func main() {
arr := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
slice1 := arr[:5]
slice2 := arr[5:]
slice3 := arr[:]
slice4 := slice1[:2]
fmt.Println(slice1)
fmt.Println(slice2)
fmt.Println(slice3)
fmt.Println(slice4)
}
输出:
[1 2 3 4 5]
[6 7 8 9 10]
[1 2 3 4 5 6 7 8 9 10]
[1 2]
append内置函数
内建函数append将元素追加到切片的末尾。若它有足够的容量,其目标就会重新切片以容纳新的元素。否则,就会分配一个新的基本数组。append返回更新后的切片,因此必须存储追加后的结果。
输入:
func main() {
arr := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
slice1 := arr[:5]
fmt.Println(slice1)
slice2 := append(slice1, 88, 99)
fmt.Println(slice2)
//对slice1追加后数值,原切片不影响
fmt.Println(slice1)
//追加后赋给原切片!!!(常用)
slice1 = append(slice1, 88, 99)
fmt.Println(slice1)
}
输出:
[1 2 3 4 5]
[1 2 3 4 5 88 99]
[1 2 3 4 5]
[1 2 3 4 5 88 99]
切片追加切片
输入:
func main() {
arr := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
slice1 := arr[:5]
//追加切片前
fmt.Println(slice1)
slice2 := arr[7:]
slice1 = append(slice1, slice2...)
//追加切片后
fmt.Println(slice1)
slice2[0] = 100
fmt.Println(slice2)
//切片slice2的变化,对slice1有影响
fmt.Println(slice1)
}
输出:
[1 2 3 4 5]
[1 2 3 4 5 8 9 10]
[100 9 10]
[1 2 3 4 5 8 9 100]
切片拷贝
输入:
func main() {
//切片拷贝
slice1 := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
slice2 := make([]int, 10)
copy(slice2, slice1)
//将slice1拷贝到slice2切片,原理是底层数组的拷贝
fmt.Println(slice2)
//验证原理
slice1[0] = 100
fmt.Println(slice1) //[100 2 3 4 5 6 7 8 9 10]
fmt.Println(slice2) //[1 2 3 4 5 6 7 8 9 10]
}
输出:
[1 2 3 4 5 6 7 8 9 10]
[100 2 3 4 5 6 7 8 9 10]
[1 2 3 4 5 6 7 8 9 10]
17.defer
使用defer来延迟一个函数或方法的执行
多个defer按照栈队列的数据结构执行
(1)defer来延迟一个函数–不传参
输入:
// defer关键字使用
func main() {
print(1)
print(2)
defer print(3)
print(4)
defer print(5)
print(6)
defer print(7)
}
func print(num int) {
fmt.Println(num)
}
输出:
1
2
4
6
7
5
3
(2)defer来延迟一个函数–传参
输入:
// defer关键字使用
func main() {
a := 0
print(a)
//代码执行到这里,参数已经传进去
defer print(a)
a++
print(a)
}
func print(num int) {
fmt.Println(num)
}
输出:
0
1
0
18.高级函数
函数本身是一个数据类型
输入:
func main() {
fmt.Printf("%T", print)
}
func print(num int) {
fmt.Println(num)
}
输出:
func(int)
因此函数可以定义赋值(引用数据类型)
输入:
func main() {
fmt.Printf("%T", print1)
var print2 func(int)
print2 = print1
fmt.Println()
//引用数据类型print2若发生变化,print1同样变化
fmt.Println(print1)
fmt.Println(print2)
print2(1)
}
func print1(num int) {
fmt.Println(num)
}
输出:
func(int)
0xe6b0e0
0xe6b0e0
1
19.匿名内部类的使用
输入:
func main() {
//匿名函数1
f1 := func() {
fmt.Println("Hello World1")
}
f1()
//匿名函数2
func() {
fmt.Println("Hello World2")
}()
//匿名函数3(直接调用自己)
func(a, b int) {
fmt.Println(a, b)
}(1, 2)
//匿名函数4(直接调用自己,带返回类型)
sum := func(a, b int) int {
return a + b
}(1, 2)
fmt.Println(sum)
}
输出:
Hello World1
Hello World2
1 2
3
20.回调函数
输出:
// 使用回调函数实现加减乘除计算
func main() {
num1 := oper(10, 3, div)
fmt.Println(num1)
//使用匿名函数实现
num2 := oper(4, 2, func(c float64, d float64) float64 {
return c / d
})
fmt.Println(num2)
}
// 回调函数
func oper(a, b float64, f1 func(float64, float64) float64) float64 {
return f1(a, b)
}
// 加操作
func add(a, b float64) float64 {
return a + b
}
// 减操作
func sub(a, b float64) float64 {
return a - b
}
// 乘操作
func mult(a, b float64) float64 {
return a * b
}
// 除操作
func div(a, b float64) float64 {
return a / b
}
输出:
3.3333333333333335
2
21.闭包函数
一个外层函数中,有内层函数,该内层函数中,会操作外层函数的局部变量且该外层函数的返回值就是这个内层函数。这个内层函数和外层函数的局部变量,统称为闭包结构。
当局部变量的生命周期就会发生改变,正常的局部变量会随着函数的调用而创建,随着函数的结束而销毁但是闭包结构中的外层函数的局部变量并不会随着外层函数的结束而销毁,因为内层函数还在继续使用!
输入:
/*
*
一个外层函数中,有内层函数,该内层函数中,会操作外层函数的局部变量且该外层函数的返回值就是这个内层函数。
这个内层函数和外层函数的局部变量,统称为闭包结构
局部变量的生命周期就会发生改变,正常的局部变量会随着函数的调用而创建,随着函数的结束而销毁但是闭包结构中的外层函数的局部变量并不会随着外层函数的结束而销毁,因为内层函数还在继续使用
*/
func main() {
//调用外部函数oper()返回内部函数
f2 := oper()
//执行内部函数,此时i的值为0,i未被销毁!(因为内层函数还在继续使用)
num1 := f2()
//输出num1为1
fmt.Println(num1)
//此时i的值为1,i仍未被销毁!
fmt.Println(f2()) //输出2,i仍未被销毁!
fmt.Println(f2()) //输出3,i仍未被销毁!
fmt.Println(f2()) //输出4,i仍未被销毁!
//调用外部函数oper()返回新的内部函数
f3 := oper()
num2 := f3()
fmt.Println(num2)
//f2()中的i值与f3()中的i值不影响!
fmt.Println(f2())
fmt.Println(f3())
}
// 外层函数
func oper() func() int {
//局部变量
i := 0
//内层函数
f1 := func() int {
//操作外层函数的局部变量
i++
return i
}
//外层函数的返回值为内层函数
return f1
}
输出:
1
2
3
4
1
5
2
22.问题处理recover函数
作用:将程序恢复正常执行,停止恐慌过程。必须与defer函数关联使用。若recover在defer的函数之外被调用,它将不会停止恐慌过程序列。
输入:
func main() {
test()
fmt.Println("test()函数执行后。。")
fmt.Println("已经做出异常处理")
}
func test() {
//通过匿名函数实现异常的获取与处理
//一般放在函数的前面,放在后面不起作用
defer func() {
//recover() 调用recover函数捕获错误,若没有错误返回nil
if err := recover(); err != nil {
fmt.Println("错误信息:", err)
}
}()
a := 10
b := 0
fmt.Println(a / b)
}
输出:
错误信息: runtime error: integer divide by zero
test()函数执行后。。
已经做出异常处理
23.自定义异常
使用errors.New(“这是一个自定义异常”)实现自定义异常
输入:
import (
"errors"
"fmt"
)
func main() {
err := zdyError()
if err != nil {
fmt.Println(err)
}
}
func zdyError() error {
err := errors.New("这是一个自定义异常")
return err
}
输出:
这是一个自定义异常
24.nil
在Go语言中,nil 是一个预声明的标识符,用来表示某些类型的零值。不同于其他语言中的 null 或 None,nil 在Go中可以用作以下类型的零值:
指针(Pointer):一个未分配到任何对象的指针。
接口(Interface):一个没有绑定任何实现的接口。
切片(Slice):一个没有分配空间的切片。
映射(Map):一个没有分配空间的映射。
通道(Channel):一个未初始化的通道。
函数(Function):一个没有被赋予任何具体实现的函数指针。
25.panic()函数
panic(err) 其中err为error类型
输入:
import (
"errors"
"fmt"
)
func main() {
err := zdyError()
if err != nil {
fmt.Println(err)
panic(err)
}
fmt.Println("ok")
}
func zdyError() error {
err := errors.New("这是一个自定义异常")
return err
}
输出:
这是一个自定义异常
panic: 这是一个自定义异常
goroutine 1 [running]:
main.main()
E:/GO/download/WindowsX86/GoWorks/src/project/0608/zidingyiyichang.go:12 +0x7b
26.time的使用
输入:
package main
import (
"fmt"
"time"
)
func main() {
fmt.Println(time.Now().Weekday())
fmt.Println(time.Now().Year())
fmt.Println(time.Now().Month())
fmt.Println(time.Monday)
fmt.Println(time.Wednesday)
fmt.Println(time.Weekday(1))
}
输出:
Monday
2024
July
Monday
Wednesday
Monday