go学习笔记
基础命令
go help: 查看帮助文档。
go help <build>
go build: 对源代码和依赖的文件进行打包,生成可执行文件
go build -o my_first_go_exe code/demo.go
go install: 编译并安装包或依赖,安装到$GOPATH/bin下
go install my_first_go_exe code/demo.go
go get: 把依赖库添加到当前module中,如果本机之前从未下载过则先下载。
go get github.com/tinylib/msgp
gfmt:格式化代码
go fmt xxx.go //预览
go fmt -w xxx.go
go version: 查看go版本号。
go env: 查看go环境信息
标识符与关键字
go变量、常量、自定义类型、包、函数的命名方式必须遵循以下规则:
- 首字符可以是任意Unicode字符或下划线。
- 首字符之外的部分可以是Unicode字符、下划线或数字。
- 名字的长度无限制,但是不建议太长。
- 不能数字开头,严格区分大小写,不能包含空格,不可以使用Go中的保留关键字
- 见名知意:增加可读性
- 下划线_本身在Go中是一个特殊的标识符,称为空标识符。可以代表任何其它的标识符,但是它对应的值会被忽略(比如:忽略某个返回值)。所以仅能被作为占位符使用,不能单独作为标识符使用。
理论上名字里可以有汉字,甚至可以全是汉字,但实际中不要这么做。
go关键字
break default func interface select case defer go map struct chan else goto package switch const if range type continue for import return fallthrough var
常量
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
变量
可以理解为昵称。
- 声明的同时赋值
var kfc string = "开封菜"
fmt.Println(kfc)
var age int = 99
fmt.Println(age)
var nb bool = false
fmt.Println(nb)
- 先声明后赋值
var game string
game = "王者荣耀"
fmt.Println(game)
变量简写
- 声明同时赋值
var name string = "kfc"
var name = "开封菜"
name := "kfc" //推荐
- 先声明后赋值
var name string
var age string
var sex string
var name,age,sex string
name = "王小明"
age = "19"
sex = "男"
- 因式分解
var (
name = "xxxx"
age = 18
salary = 3000
gender string // 只声明但不赋值,有一个默认: ""
length int // 只声明但不赋值,有一个默认: 0
gay bool // 只声明但不赋值,有一个默认: false
)
fmt.Println(name,age,hobby,salary,gender,length,gay)
- 全局变量和局部变量
全局变量未写在函数中的变量称为全局变量,不可以用v1:=xx简写,可以用因式分解方式声明多个变量;项目中寻找变量时最后一环,可以只定义不调用
局部变量写在{}里面的变量;可以使用任意方式简化;可以使用因式分解方式声明多个变量,定义必须调用
package main
import "fmt"
//全局变量
var city string = "beijing" //可以
var city1 = "shanghai" //可以
var (
name = "kfc"
price = 3.1
number = 2
)
// city := "nanjing" 不可以
func main() {
name := "xxxx" //局部变量
fmt.Println(name)
if true {
name := "kfc" //局部变量
fmt.Println(name)
}
fmt.Println(name)
fmt.Println(city)
fmt.Println(city1)
fmt.Println(price, name, number)
}
- 赋值与内存相关
使用int、string、bool这三种数据类型时,如果遇到变量的赋值则会拷贝一份。【值类型】与python不同
常量
不可被修改的变量。
package main
import "fmt"
const (
level = "2"
ya = "亚"
)
const pi = 3.14
const age int = 98
func main() {
//定义常量
const name = 1
const type1 string = "str"
fmt.Println(type1)
fmt.Println(name)
//常量因式分解
const (
v1 = 134
v2 = 456
v3 = 789
)
fmt.Println(v1, v2, v3, pi, level, ya, age)
}
}```
### iota
当做一个在声明常量时的一个计数器。
```go
package main
import "fmt"
func main() {
const (
mon1 = iota + 1
mon2
mon3
mon4
mon5
)
fmt.Println(mon1, mon2, mon3, mon4, mon5)
//默认iota=0,+1后打印输出为12345
const (
m1 = iota
m2
_
m3
)
fmt.Println(m1, m2, m3)
//当中间有不想输出的数,可以通过-跳过,打印输出为013
}
go语言的数据类型
基础数据类型
类型 | 长度(字节) | 默认值 | 说明 |
---|---|---|---|
bool | 1 | false | |
byte | 1 | 0 | uint8,取值范围[0,255] |
rune | 4 | 0 | Unicode Code Point, int32 |
int, uint | 4或8 | 0 | 32 或 64 位,取决于操作系统 |
int8, uint8 | 1 | 0 | -128 ~ 127, 0 ~ 255 |
int16, uint16 | 2 | 0 | -32768 ~ 32767, 0 ~ 65535 |
int32, uint32 | 4 | 0 | -21亿~ 21亿, 0 ~ 42亿,rune是int32 的别名 |
int64, uint64 | 8 | 0 | |
float32 | 4 | 0.0 | |
float64 | 8 | 0.0 | |
complex64 | 8 | ||
complex128 | 16 | ||
uintptr | 4或8 | 以存储指针的 uint32 或 uint64 整数 |
布尔类型
package main
import "fmt"
func main() {
// 布尔类型,表示真假
// 标识符bool
// 字面量:false bool
// 零值默认 false var zero bool
isgirl := false
isboy := true
fmt.Println(zero, isgirl, isboy)
}
逻辑运算符
package main
import "fmt"
var zero bool
const (
isGirl = false
isBoy = true
)
func main() {
fmt.Println("&&") //只要有一个false则为false
fmt.Println(true && true) //true
fmt.Println(true && false) //false
fmt.Println(false && false) //false
fmt.Println(false && true) //false
fmt.Println("||") //只要有一个为true则为true
fmt.Println(true || true) //true
fmt.Println(true || false) //true
fmt.Println(false || false) //false
fmt.Println(false || true) //true
fmt.Println("!") //取反
fmt.Println(!true) //false
fmt.Println(!false) //true
fmt.Println(!isGirl) //true
fmt.Println(!isBoy) //false
// 关系运算(== ,!=)
fmt.Println("关系运算")
fmt.Println(isGirl == isBoy) //false
fmt.Println(isGirl != isBoy) //true
fmt.Println(isBoy == zero) //false
//格式化输出
fmt.Printf("%T,%s,%t,%t\n", isBoy, isGirl, isGirl, isBoy) //输出:bool,%!s(bool=false),false,true %!s说明占位类型不符
}
整数int
package main
import "fmt"
func main() {
var age int = 17
fmt.Printf("%T,%d\n", age, age)
//算术运算
fmt.Println(3 + 10) //13
fmt.Println(10 - 3) //7
fmt.Println(5 * 8) //40
fmt.Println(9 / 2) //4
fmt.Println(9 % 2) // 1
age++
fmt.Println(age) //18
age--
fmt.Println(age) //17
//关系运算符
fmt.Println(2 == 3) //false
fmt.Println(2 != 3) //true
fmt.Println(2 > 3) //false
fmt.Println(2 < 3) //true
fmt.Println(2 >= 3) //false
fmt.Println(2 <= 3) // true
//赋值运算
num := 2
num += 3
fmt.Println(num) //5
num *= 2
fmt.Println(num) //10
num -= 5
fmt.Println(num) // 5
num /= 4
fmt.Println(num) // 1
// 类型转换
var intA int = 10
var intB uint = 20
//fmt.Println(intA + intB) invalid operation: intA + intB (mismatched types int and uint) 类型不同不能相加,go语言中需要强制转换
// 大转小可能出现溢出
fmt.Println(intA + int(intB)) //30
fmt.Println(uint(intA) + intB) //30
}
字符
func defaultValue() {
//普通字符
var c1 byte = 'A'
fmt.Println(c1) //65
var c2 byte = '6'
fmt.Println(c2) //54
var c3 int = '中'
fmt.Println(c3) //20013
fmt.Println(c3 / 20) //1000
fmt.Printf("c3对应的类型是:%c\n", c3) //中
//特殊字符
fmt.Println("回车换行")
fmt.Println("aaa\nbbb")
fmt.Println("退格")
fmt.Println("aa\bbbb")//abbb
fmt.Println("光标回到本行开头,后续输入替换原有字符")
fmt.Println("aaa\rbbb")//bbb
fmt.Println("制表符")
fmt.Println("aaa\tbbb")//aaa bbb
fmt.Println("转义冒号")
fmt.Println("\"goland\"")//"goland"
}
字符串
func main() {
var s1 string = "hello golang"
fmt.Println(s1)
var s2 string = "abc"
s2 = "def"
//s2[0] = v 错误用法,字符串不可变,无法更改
fmt.Println(s2)
var s3 string = "efgh"
fmt.Println(s3) //普通字符串用双引号
var s4 string = `
func main() {
// 布尔类型,表示真假 // 标识符bool
// 字面量:false bool
// 零值默认 false var zero bool isgirl := false
isboy := true
fmt.Println(zero, isgirl, isboy)
}
`
fmt.Println(s4) //有特殊字符用反引号`
var s5 string = "abc" + "efg" //字符串拼接效果
fmt.Println(s5) //过长换换行要把+号留在上一行末尾
var s6 string = "abc" + "efg" + "abc" +
"efg" + "efg" + "abc" + "efg" +
"efg" + "abc" + "efg" + "efg" + "abc" +
"efg" + "efg" + "abc" + "efg" + "efg" +
"abc" + "efg" + "efg" + "abc" + "efg"
fmt.Println(s6)
}
默认值
func main() {
var a int //0
var b float64 //0
var c bool //false
var d string //''空
var e float32 //0
fmt.Println(a, b, c, d, e)
}
普通数据类型转string
func main() {
//方法1: Sprintf var n1 int = 19
var n2 float32 = 4.78
var n3 bool = true
var n4 byte = '@'
var s1 string = fmt.Sprintf("%d", n1)
var s2 string = fmt.Sprintf("%f", n2)
var s3 string = fmt.Sprintf("%t", n3)
var s4 string = fmt.Sprintf("%c", n4)
fmt.Printf("s1的格式为%T,它的值为%v\n", s1, s1) //%v通用占位符,万能
fmt.Printf("s2的格式为%T,它的值为%q\n", s2, s2) //%q会自动将值用引号括起来
fmt.Printf("s3的格式为%T,它的值为%q\n", s3, s3)
fmt.Printf("s4的格式为%T,它的值为%q\n", s4, s4)
// 方法2:strconv
var n5 int = 18
var n6 float64 = 4.29
var n7 bool = false
var s5 string = strconv.FormatInt(int64(n5), 10) //参数:第一个参数必须转为int64类型,第二个为进制
fmt.Printf("s5的格式为%T,它的值为%v\n", s5, s5)
var s6 string = strconv.FormatFloat(n6, 'f', 4, 64)
//参数2 ‘f’代表(-ddd.dddd),第三个参数为保留小数后4位,第四个参数表示是float64位
fmt.Printf("s6的格式为%T,它的值为%v\n", s6, s6)
var s7 string = strconv.FormatBool(n7)
fmt.Printf("s7的歌手为%T,它的值为%v\n", s7, s7)
}
string转普通数据类型
func main() {
//string-->bool
var s1 string = "true"
var a bool
a, _ = strconv.ParseBool(s1)
fmt.Printf("a type is %T ,a is %t\n", a, a)
/*ParseBool这个函数的返回值有两个:(value bool, err error)
value就是我们得到的布尔类型的数据,err出现的错误
我们只关注得到的布尔类型的数据,err可以用_直接忽略*/
//string--> int64 var s2 string = "2019"
var b int64
b, _ = strconv.ParseInt(s2, 10, 64)
fmt.Printf("b type is %T ,b is %v\n", b, b)
//string--> float32/float64
var s3 string = "3.14"
var c float64
c, _ = strconv.ParseFloat(s3, 64)
fmt.Printf("c type is %T ,c is %v\n", c, c)
//注意:string向基本数据类型转换的时候,一定要确保string类型能够转成有效的数据类型,
//否则最后得到的结果就是按照对应类型的默认值输出
var s4 string = "golang"
var d bool
d, _ = strconv.ParseBool(s4)
fmt.Printf("d type is %T ,d is %v\n", d, d) //false
var s5 string = "012"
var e int64
e, _ = strconv.ParseInt(s5, 10, 64) //0 参数2为base进制,如果为0则自行根据字符串判断
fmt.Printf("e type is %T ,e is %v\n", e, e)
}
复杂数据类型
指针
func main() {
var age int = 11
println(&age) //age变量内存的地址
//指针变量
var ptr *int = &age
fmt.Println(ptr)
fmt.Printf("ptr本身的空间地址为:%v", &ptr) //取内存地址
fmt.Printf("ptr指向的值为:%v", *ptr) //*根据地址取值
//可以通过指针改变指向值
var n1 int = 10
fmt.Println(n1)
var ptr2 *int = &n1
// var ptr2 *int = n1 错误用法:指针变量接收的一定是地址值
*ptr2 = 20
fmt.Println(n1)
n2 := 10
fmt.Println(n2)
// var ptr3 *float32 = &n2 错误用法变量地址
var ptr3 *int = &n2
println(ptr3) //基本数据类型(又叫值类型),都有对应的指针类型,形式为*数据类型,
//比如int的对应的指针就是*int, float32对应的指针类型就是*float32。依次类推
}
运算符优先级
![[Pasted image 20241203112128.png]]
获取用户终端输入
func main() {
var age int
fmt.Println("please input age:")
fmt.Scanln(&age)
var name string
fmt.Println("please input name:")
fmt.Scanln(&name)
var score float32
fmt.Println("please input score:")
fmt.Scanln(&score)
var isVip bool
fmt.Println("please input isVip:")
fmt.Scanln(&isVip)
//方法1
fmt.Printf("年龄:%v,名字:%v,分数:%v,是否是vip:%v", age, name, score, isVip)
//方法2
//fmt.Println("请输入对应信息:空格分隔")
//fmt.Scanf("%d %s %f %t", &age, &name, &score, &isVip) //fmt.Printf("年龄:%v,名字:%v,分数:%v,是否是vip:%v", age, name, score, isVip)
}
流程控制
if分支
switch分支
func main() {
var score int = 15
switch score {
case 1:
fmt.Println("you are no.1")
case 2:
fmt.Println("you are no.2")
case 3, 4, 5:
fmt.Println("you are no.3")
default:
fmt.Println("you are zero")
fallthrough
case 6:
fmt.Println("you are no.6")
}
}
- switch后是一个表达式(即:常量值、变量、一个有返回值的函数等都可以)
- case后面的值如果是常量值(字面量),则要求不能重复
- case后的各个值的数据类型,必须和 switch 的表达式数据类型一致
- case后面可以带多个值,使用逗号间隔。比如 case 值1,值2...
- case后面不需要带break
- default语句不是必须的,位置也是随意的
- switch后也可以不带表达式,当做if分支来使用
- switch后也可以直接声明/定义一个变量,分号结束,不推荐
- switch穿透,利用fallthrough关键字,如果在case语句块后增加fallthrough ,则会继续执行下一个case,也叫switch穿透。
for循环
for循环写法
var str string = "hello goland,你好"
//方法1
var i int = 0
for i < len(str) {
fmt.Printf("%c\n", str[i])
i++
}
//方法2
for j :=1 ;j < len(str);j++{
fmt.Printf("%c\n", str[j])
}
for 死循环
func main() {
//1
for {
fmt.Println("NI hao")
}
//2
for ;; {
fmt.Println("NI hao")
}
}
for range
for _, value := range str {
fmt.Printf("%c\n", value)
}
for index, value := range str {
fmt.Printf("下标:%d 它的值为:%c\n", index, value)
}
break
func main() {
for i := 1; i <= 3; i++ {
for j := 1; j <= 3; j++ {
if j == 2 {
break
}
println(i, j)
}
}
}
//输出
11
21
31
continue
func main() {
for i := 1; i <= 3; i++ {
for j := 1; j <= 3; j++ {
if j == 2 {
continue
}
println(i, j)
}
}
}
//输出
11
13
21
23
31
33
goto
func main() {
println("hello goto1")
println("hello goto2")
println("hello goto3")
if 1 == 1 {
goto label //通常搭配条件判断使用
}
println("hello goto4")
println("hello goto5")
label:
println("hello goto6")
println("hello goto7")
println("hello goto8")
}
return
package main
func main() {
for i := 1; i <= 100; i++ {
println(i)
if i == 14 {
return //直接结束函数,不执行下面代码
}
}
println("hello world")
}
函数
函数名
遵循标识符命名规范:见名知意 addNum,驼峰命名addNum
首字母不能是数字
首字母大写该函数可以被本包文件和其它包文件使用(类似public)
首学母小写只能被本包文件使用,其它包文件不能使用(类似private)
形参列表
形参列表:个数:可以是一个参数,可以是n个参数,可以是0个参数
形式参数列表:作用:接收外来的数据
实际参数:实际传入的数据
func jia(a int, b int) int { //1个返回值,括号可以省略
result := a + b
return result
}
func chenchu(a int, b int) (int, int) { //俩个返回值
mul := a * b
divide := a / b
return mul, divide
}
func none(a int, b int) { //无返回值可以省略类型
var c int
c = a * b
fmt.Println("this is result:%d", c)
}
func main() {
num1 := jia(10, 2)
num2, num3 := chenchu(100, 2)
num4, _ := chenchu(10, 2) //不想接受其他返回值,可以省略
none(7, 5)//35
fmt.Println(num1, num2, num3, num4)//12,200,50,20
}
其他特性
- Golang中函数不支持重载(不能定义俩个相同的函数,会报错)
- Golang中支持可变参数
func test(nums ...int) {
for _, n := range nums {
fmt.Println(n)
}
}
func main() {
fmt.Println("-----------------")
test(1, 2, 3, 45, 6)
fmt.Println("-----------------")
test()
fmt.Println("-----------------")
test(8)
}
- 基本数据类型和数组默认都是值传递的,即进行值拷贝。在函数内修改,不会影响到原来的值。
func res(num int) {
num = 30
fmt.Println("res-------", num)
}
func main() {
var num int = 10
res(num)
fmt.Println("main---------", num)
}
- 在Go中,函数也是一种数据类型,可以赋值给一个变量,则该变量就是一个函数类型的变量了。通过该变量可以对函数调用
func dayin(num int) {
fmt.Println(num)
}
func main() {
a := dayin
a(10)
fmt.Printf("dayin的数据类型是,%T,a的数据类型是,%T", dayin, a)
}
- 为了简化数据类型定义,Go支持自定义数据类型
基本语法: type 自定义数据类型名 数据类型
可以理解为 : 相当于起了一个别名
func main() {
var a int = 5
type myInt int
var b myInt = 6
fmt.Printf("a的数据类型是%T,b的数据类型是%T\n", a, b)
//result04 := a + b 数据类型不匹配
result04 := myInt(a) + b
fmt.Println(result04)//11
}
- 支持对函数返回值命名
func test02(num1 int, num2 int) (int, int) { //传统写法要求:返回值和返回值的类型对应,顺序不能差
result01 := num1 * num2
result02 := num1 + num2
return result01, result02
}
func test03(num1 int, num2 int) (sum int, sub int) { //升级写法:对函数返回值命名,里面顺序就无所谓了,顺序不用对应
sub = num1 - num2
sum = num1 + num2
return
}
func main() {
A, _ := test02(5, 6)
B, c := test03(5, 6)
fmt.Println(A, B, c)//30 11 -1
}
- 函数既然是一种数据类型,因此在Go中,函数可以作为形参,并且调用
(把函数本身当做一种数据类型)
// 定义一个函数:
func nmu1(num int) {
fmt.Println("this is nmu1")
}
// 定义一个函数,将另一个函数作为形参进来
func nmu2(num3 int, num4 int, b func(int)) {
fmt.Println("this is nmu2")
}
func main() {
//函数也是一个数据类型,可以赋值给变量
b := nmu1
fmt.Printf("%T,%T", b, nmu1)
//通过该变量可以函数进行调用
b(10) //等价于nmv1(10)
//调用函数2
nmu2(7, 9, nmu1)
nmu2(5, 8, b)
}
包
在程序层面,所有使用相同 package 包名 的源文件组成的代码模块。在源文件层面就是一个文件夹
打包语法:package 包名
- package进行包的声明,建议:包的声明这个包和所在的文件夹同名
- main包是程序的入口包,一般main函数会放在这个包下,main函数一定要放在main包下,否则不能编译执行
- 引入包的语法:import "包的路径",包名是从$GOPATH/src/后开始计算的,使用/进行路径分隔。
- 如果有多个包,建议一次性导入
- 函数名,变量名首字母大写,函数,变量可以被其它包访问
- .在函数调用的时候前面要定位到所在的包
- .一个目录下不能有重复的函数
- 包不允许自我导入
- 包名和文件夹的名字,可以不一样
- 一个目录下的同级文件归属一个包,同级别的源文件的包的声明必须一致
- 可以给包取别名,取别名后,原来的包名就不能使用了
import ( //一次性导入所有包
"fmt"
"src/cloudy"
est "src/gotofish" //别名
)
func main() {
cloudy.Getsunny()
fmt.Println("who are they?")
//aaa.Gettool() 包名可以和目录名不一致
est.Gettool()//设置包的别名后,原来的包名无法使用
}
init函数
init函数:初始化函数,可以用来进行一些初始化的操作
每一个源文件都可以包含一个init函数,该函数会在main函数执行前,被Go运行框架调用。
一个包被多个其他包导入,它的 init
函数只会被执行一次。
import (
"fmt"
aaa "src/gotofish"
)
var a int = test()
// a := test() 短变量声明不能用于包级别
func test() int {
fmt.Println("test 函数被执行")
return 10
}
func init() {
fmt.Println("main init函数被执行")
}
func main() {
fmt.Println("main.go 函数被执行")
fmt.Printf("name:%s,nianling:%d sex:%s", aaa.Name, aaa.Age, aaa.Sex)
}
//多个源文件都有初始化函数,执行顺序是:
- 导入包的初始化(包级别变量声明=> `init` 函数)
- 主包(`main` 包)的初始化(包级别变量声明=> `init` 函数)
- 然后是 `main` 函数的执行
匿名函数
匿名函数的定义
func main() {
result := func(num1 int, num2 int) int {
return num1 * num2
}(10, 50) //定义一个匿名函数的同时并调用
fmt.Println(result)
}
匿名函数的调用
func main() {
result := func(num1 int, num2 int) int {
return num1 * num2
}
result1 := result(7, 9)
fmt.Println(result1)
result2 := result(8, 35)
fmt.Println(result2)
}
匿名函数的全局调用
var Fun1 = func(num1 int) int {
num2 := num1 + 5
return num2
}
func main() {
fmt.Println(Fun1(5)) //10
fmt.Println(Fun1(8)) //13
fmt.Println(Fun1(9)) //14
}
闭包
- 闭包就是一个函数和与其相关的引用环境组合的一个整体(匿名函数+引用的变量/参数 = 闭包)
- 闭包不可滥用(对内存消耗大)
//Getsum:函数名 ()空形参 返回值是一个匿名函数,这个匿名函数的参数是int,返回值也是int
func Getsum() func(num int) int {
var sum int = 0
return func(num int) int {
sum += num
return sum
}
}
func Getsum01(sum, num2 int) int {
sum = sum + num2
return sum
}
func main() {
f := Getsum()
fmt.Println(f(5)) //5
fmt.Println(f(10)) //15
fmt.Println(f(26)) //41
fmt.Println(f(17)) //58 匿名函数中引用的那个变量会一直保存在内存中,可以一直使用
fmt.Println("---------不使用闭包如何实现-------------------")
fmt.Println(Getsum01(0, 5)) //5
fmt.Println(Getsum01(5, 10))//15
fmt.Println(Getsum01(15, 26))//41
fmt.Println(Getsum01(41, 17))//58
}
defer关键字
- 在函数中,程序员经常需要创建资源,为了在函数执行完毕后,及时的释放资源,Go的设计者提供defer关键字
- 遇到defer关键字,会将后面的代码语句压入栈中,也会将相关的值同时拷贝入栈中,不会随着函数后面的变化而变化
- defer有延迟执行机制(函数执行完毕再执行defer压入栈的语句)
func add(num1, num2 int) int {
//遇到关键字defer,将后面语句压入栈中
defer fmt.Println("num1=", num1)
defer fmt.Println("num2=", num2)
sum := num1 + num2
fmt.Println("sum=", sum)
return sum
}
func main() {
fmt.Println(add(1, 2))
}
//sum=3,
//num2=2,
//num1=1,//函数语句执行完毕,遵循栈的特点,先进后出原则
//3
func sub(num1, num2 int) int {
defer fmt.Println("num1=", num1) //遇到defer关键字,会将后面的代码语句压入栈中,也会将相关的值同时拷贝入栈中,不会随着函数后面的变化而变化
defer fmt.Println("num2=", num2)
num1 += 60 //120
num2 += 90 //147
var sub int
sub = num1 - num2
fmt.Println("sub=", sub)
return sub
}
func main() {
//fmt.Println(add(1, 2))
fmt.Println(sub(60, 57))
}
//sub= -27
//num2=57
//num1=60
//-27
系统函数
字符串函数
len(str)
str := "gland你好"
fmt.Println(len(str)) //11
循环写法
(1)利用方式1:for-range键值循环
(2)r:=[]rune(str)
func main() {
str := "gland你好"
fmt.Println(len(str)) //11
//方法1
for i, value := range str {
fmt.Println(i, "索引的值为:", string(value))
}
fmt.Println("-------------------------------------------")
//方法2
r := []rune(str)
for i := 0; i < len(r); i++ {
fmt.Printf("%c\n", r[i])
}
}
字符串转换
整数转换
func main() {
n := 'A' //单引号字符,
fmt.Println(int(n)) //int转换对应的ascll码值
//转整数
q := "1967"
m, _ := strconv.Atoi(q)
//fmt.Println(int(m)) 无法直接转成int使用
fmt.Printf("%T,%T,%d\n", q, m, m) //string int 1967
//转字符串
o := 1967
p := strconv.Itoa(o)
fmt.Printf("%T,%T,%v\n", o, p, p) //int,string,1967
}
大小写转换
func main() {
str := "Hello world ,This is golang"
//转大写
fmt.Println(strings.ToUpper(str))
//转小写
fmt.Println(strings.ToLower(str))
}
字符串查找
func main() {
str := "abcdefg,higklmn,goland,golang"
//统计字符串出现次数
fmt.Println(strings.Count(str, "go")) //2
fmt.Println(strings.Count(str, "p")) //0
//查子串的下标
fmt.Println(strings.Index(str, "g")) //6
fmt.Println(strings.Index(str, "p")) //-1
}
字符串判断
func main() {
str := "http://study.goland.org"
//判断是否存在字符串中
fmt.Println(strings.Contains(str, "go")) //true
fmt.Println(strings.Contains(str, "python")) //false
//判断是否以xx开头
fmt.Println(strings.HasPrefix(str, "go")) //false
fmt.Println(strings.HasPrefix(str, "h")) //true
fmt.Println(strings.HasPrefix(str, "http://")) //true
//判断是是否已xx结尾
fmt.Println(strings.HasSuffix(str, "g")) //true
fmt.Println(strings.HasSuffix(str, ".org")) //true
fmt.Println(strings.HasSuffix(str, ".com")) //false
//不大小写判断
fmt.Println(strings.EqualFold("GO", "go")) //true
//区分大小写判断
fmt.Println("go" == "GO") //false
}
字符串的修改
func main() {
str := " hello,go,goenv,go,gopath,goland,gobulid "
// -1 代表全部替换
fmt.Println(strings.Replace(str, "go", "py", -1))
fmt.Println(strings.Replace(str, "go", "python", 1))
// 以,号分割,分割成一个数组
arr := strings.Split(str, ",")
fmt.Println(arr)
//去左右空格
fmt.Println(strings.TrimSpace(str))
//去掉特定字符
str2 := "~hello world~"
//去左右字符
fmt.Println(strings.Trim(str2, "~"))
fmt.Println(strings.TrimLeft(str2, "~"))
fmt.Println(strings.TrimRight(str2, "~"))
//移除以特定字符串开头的前缀,如果是则移除,不是以特定字符串开头,则返回原字符串
fmt.Println(strings.TrimPrefix(str, "go"))
fmt.Println(strings.TrimPrefix(str, " hello"))
//移除以特定字符串开头的后缀,如果是则移除,不是以特定字符串开头,则返回原字符串
fmt.Println(strings.TrimSuffix(str2, "go"))
fmt.Println(strings.TrimSuffix(str2, "world~"))
}
/*
hello,py,pyenv,py,pypath,pyland,pybulid
hello,python,goenv,go,gopath,goland,gobulid
[ hello go goenv go gopath goland gobulid ]
hello,go,goenv,go,gopath,goland,gobulid
hello world
hello world~
~hello world
hello,go,goenv,go,gopath,goland,gobulid
,go,goenv,go,gopath,goland,gobulid
~hello world~
~hello
*/
日期函数和时间函数
当前时间
func main() {
now := time.Now()
fmt.Println(now)
fmt.Printf("当前时间为:%v,当前的类型为%T\n", now, now) //当时的类型为time.Time
fmt.Printf("年:%v \n", now.Year())
fmt.Printf("月:%v \n", now.Month())
fmt.Printf("日:%v \n", now.Day())
fmt.Printf("时:%v \n", now.Hour())
fmt.Printf("分:%v \n", now.Minute())
fmt.Printf("秒: %v \n", now.Second())
fmt.Println("-----------------------------------------------------------")
}
日期的格式化
//格式化输出1,printf返回多个值,无法直接定义,sprintf返回字符串
date_tiem := fmt.Sprintf("当前年月日为:%v,%v,%v,当前时分秒为:%v,%v,%v", now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second())
fmt.Println(date_tiem)
//格式化输出,数字是固定的,符合可以自定义,时分秒也是可自定义的
date_time := now.Format("2006-01-02 15:04:05")
fmt.Println(date_time)
date_time1 := now.Format("2006 15/04")
fmt.Println(date_time1)
内置函数
new()
func main() {
str := "hello world"
fmt.Println(len(str))
//new()分配内存,主要填数据类型(int系列,float系列,bool,string,数组和结构体)
snow := new(int)
fmt.Printf("snow的类型是:%T,snow的值是:%v,snow的地址是:%v,snow指针指向的值:%v", snow, snow, &snow, *snow)
}
make()
异常处理
defer+recover捕获
func test() {
defer func() {
err := recover() //捕获异常
if err != nil {
fmt.Println("异常已经捕获...")
fmt.Println("err是:", err)
}
}() //这个括号表示执行匿名函数的执行
num1 := 10
num2 := 0
result := num1 / num2
fmt.Println("result is", result)
}
func main() {
test()
fmt.Println("test函数这执行了")
fmt.Println("开始处理接下来的函数了...")
}
自定义异常
func test1() (err error) { //错误类型是error
num1 := 10
num2 := 0
if num2 == 0 {
return errors.New("除数不能为零!")
} else {
res := num1 / num2
fmt.Println(res)
return nil
}
}
func main() {
err := test1()
if err != nil {
fmt.Println("自定义错误是:", err)
}
fmt.Println("test函数这执行了")
fmt.Println("开始处理接下来的函数了...")
}
数组
数组内存分析
func main() {
var arr [3]int //定义一个数组,【】里面是数组长度
fmt.Println(arr)
fmt.Println(len(arr), cap(arr)) // 长度3、 容量3
fmt.Printf("arr的地址是:%p\n", &arr) //这里用%v显示的是字面量,不是地址,建议所有显示地址的都用%p
fmt.Printf("arr0的地址是:%v\n", &arr[0])
fmt.Printf("arr1的地址是%v\n", &arr[1])
fmt.Printf("arr2的地址是%v\n", &arr[2])
}
数组遍历
func main() {
var arr1 [3]int
for i := 0; i < len(arr1); i++ {
fmt.Printf("请输入%d位的同学成绩为:", i+1)
fmt.Scanln(&arr1[i])
}
//第一种循环
fmt.Println("----------") //注意直接用小写println可能会导致横线提前输出,这是由于`println` 函数和 `fmt.Printf` 函数的混合使用以及可能存在的缓冲问题导致的
for j := 0; j < len(arr1); j++ {
fmt.Printf("第%d位同学的成绩为:", j+1)
fmt.Printf("%d\n", arr1[j])
}
//第二种
fmt.Println("----------")
for key, value := range arr1 {
fmt.Printf("第%d位同学的成绩为:%d\n", key+1, value)
}
}
数组的初始化
func main() {
var array1 [3]int = [3]int{1, 2, 3}
fmt.Println(array1)
var array2 = [3]int{7, 8, 9}
fmt.Println(array2)
var array3 = [...]int{77, 88, 99, 100}
fmt.Println(array3)
var array4 = [...]int{0:22,2:33,1:55,3:4,5} //长度为5
var array4 = [...]int{0:22,2:33,1:55,4:77,5} //长度为6,下标3忽略为0
// var array4 = [...]int{0:22,2:33,1:55,4,5} 会报重复索引,前提是如果前面的下标颠倒,后面的必须是指定值或者按照正确下标指定,否则报错
fmt.Println(array4)
}
注意事项
func main() {
//长度是类型的一部分
var arr1 [5]string
fmt.Printf("数组1的类型是%T\n", arr1) //类型是 [5]string var arr2 [5]int
fmt.Printf("数组2的类型是%T\n", arr2) // [5]int
//值传递
var arr3 = [3]int{3, 6, 9}
test1(arr3)
fmt.Println(arr3)
//引用传递
test2(&arr3)
fmt.Println(arr3)
}
func test1(arr [3]int) {
arr[0] = 100
}
func test2(arr *[3]int) {
arr[0] = 100
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性