考完研了,最近在学校安排的培训机构实习(懂得都懂),培训机构有几个方向,我选了go语言后端(本人java很烂,尚硅谷200个小时的视频我是真看不下去),本文记录一下go语言的语法基础。
还有就是,本博文的学习资料来源是菜鸟教程和枫枫知道的博文,后面会附上链接。
他们就相当于字典,面面俱到,本博文就相当于笔记,写一些注意事项,适合有其他语言基础的快速熟悉go语言,我主要是写一些需要注意的地方,这是我与他们不一样的地方
菜鸟教程-go语言
枫枫知道博客
枫枫知道B站go语言教程
换行输出
fmt.Println()
格式化输出
fmt.Printf()
%v 按值的本来值输出
%#v 输出GO语言语法格式的值
%T 输出GO语言语法格式的类型和值
%b 整型以二进制方式显示
%o 整型以八进制方式显示
%d 整型以十进制方式显示
%x 整型以十六进制方式显示
%X 整型以十六进制、字母大写方式显示
%f 浮点数
%p 指针,十六进制方式显示
%c 该值对应的unicode码值
输入
var a int//首先定义一个变量
fmt.Scan(&a)//然后写输入函数,记得带指针
单行注释
//
多行注释
/*
*/
数字类型分为整型和浮点型,这个在其他语言里面也有,不再说了。
这里只想强调几点
1.我上面写的所有数据类型,请分别看成是一种数据类型,就是int是int,int8是int8,他们不是等价的
2.没有特殊需求,整数用int其实就行了。
3.uint是无符号整数,具体什么是无符号整数,百度或gpt吧,要是详细说都能写篇写小作文了。
其他语言也有布尔类型,这里依然只想强调1点
go语言里面跟很多语言也是一样的,分为byte和string类型,
在这个基础上,go语言还有个rune类型。
然后就是强调环节
go语言不像python,对于byte类型和string类型区别不明显。
在go语言里面,byte必须用 ‘’,也就是单引号给引起来
string类型使用双引号给引起来,如果需要输入很多文字,使用反单引号给引起来,也就是1左边的那个符号
var a byte = 'a'
fmt.Printf("%c %d\n", a, a)
var a1 uint8 = 97
fmt.Printf("%c %d\n", a1, a1)
go语言里面的源码
rune这种数据类型跟byte的作用差不多,用来转换对应的码
var z rune = '中'
fmt.Printf("%c %d\n", z, z)
还有就是默认值问题,在go语言里面,如果你声明了一个变量,但是没有赋值,那么这个变量的值就是对应变量的零值
int就是0, bool就是false,字符串就是""
var n string
var age int
var sex bool
fmt.Printf("%#v\n", n)
fmt.Printf("%#v\n", age)
fmt.Printf("%#v\n", sex)
这里想说的是,
常量使用const来声明,必须在声明的时候就初始化,且一但初始化后就不能修改。
还有就是变量的声明,go语言的类型是在写后面,如果你之前写过java,刚开始应该是不太适应,写多了慢慢就适应了。
变量的声明有多种写法,选一个你喜欢的写就行了。这里也会写一些几种变量的声明。
//指定变量的类型
var a string = "hello world"
var b int = 1
var c, d int = 1, 2
//自行推断类型
var a = 1
a := 50
//先声明变量,后初始化
var a int
a = 1
注:后面的数组,切片,map等还可以使用make初始化
数组类型就很像java里面的静态数组,确定大小后就不能改了,
想要扩大就要写代码来扩大数组,限制比较多。然后这个数组类型也支持索引,但是不支持逆向索引(就是从后面往前面数是,-1,-2,-3,…),下面写一个代码就行了
还有就是要注意边界值!!!
var nameList [3]string = [3]string{"ss", "aa", "bb"}
fmt.Println(nameList)
//索引,go语言没有逆向索引
fmt.Println(nameList[0])
fmt.Println(nameList[2])
fmt.Println(nameList[len(nameList)-1])
这里想说的就是,go语言里面初始化数据类型的方式比较多,选一个自己喜欢的写法就行了。
切片类型(Slice)就很像python里面的list,也就是动态数组
关于切片需要注意两个问题
1.长度和容量问题
在go语言里面长度指的是这个切片里面有多少个元素,容量是指底层里面可以装多少个元素。
我个人理解是,就相当于水杯,长度就是水杯里面有多少水,容量就是,这个杯子最大可以装多少水。
然后就是,切片类型当然支持自动扩容。
2.引用问题
切片是引用类型,切片是引用类型,多个切片可以引用同一个底层数组。修改一个切片的元素可能会影响其他引用了同一底层数组的切片。
关于切片就说这么多,这个需要多练,才能掌握。
map类型就是python里面的字典
这里还是要说一下,创建map依然有好几个写法,选一个自己喜欢的写就行了
var usermap = map[int]string{
1: "枫枫",
2: "张三",
4: "",
}
fmt.Println(usermap)
fmt.Println(usermap)
//增加
usermap[5] = "你好"
fmt.Println(usermap)
delete(usermap, 4)
fmt.Println(usermap)
usermap[1] = "枫枫知道"
fmt.Println(usermap)
fmt.Println(usermap[1])
map必须初始化才能使用
var amap map[string]string
amap["name"] = "枫枫"
fmt.Println(amap)
我是觉得跟c语言里面的指针是一模一样,请看下面这段代码
var ip *int
var a int
fmt.Scan(&a)
func deliver2(num *int) int {
*num += 1
return *num
}
跟c语言是不是一模一样
关于运算符,go语言里面该有的都有,这里依然只强调几点
1.go语言里面只有右++,没有左++,减减也是一样的(说说实话,我是觉得左右加加减减是不利于代码维护以及阅读,这样只有一个反而好一点,就那个左右加加减减的面试题,现在让我做我也不一定做的对)
这里只想写个写法,跟其他有没有除了写法没有其他区别
如果你学过其他语言,稍微看一下就行了
if 布尔表达式 {//是的,条件这里没有括号
/* 在布尔表达式为 true 时执行 */
}
if 布尔表达式 {
/* 在布尔表达式为 true 时执行 */
} else {
/* 在布尔表达式为 false 时执行 */
}
if 布尔表达式 {
/* 在布尔表达式为 true 时执行 */
} else if 布尔表达式 {
/* 在布尔表达式为 true 时执行 */
} else {
/* 在布尔表达式为 false 时执行 */
}
//中断式 谓语句
if age <= 0 {
fmt.Println("未出生")
return
}
if age <= 18 {
fmt.Println("未成年")
return
}
if age <= 35 {
fmt.Println("青少年")
return
}
fmt.Println("中年")
//嵌入式写法
if age <= 18 {
if age <= 0 {
fmt.Println("未出生")
} else {
fmt.Println("未成年")
}
} else {
if age <= 35 {
fmt.Println("青年")
} else {
fmt.Println("中年")
}
}
这里要注意
1.go语言里面的switch case 默认case后面自带break(是的,不会出现java里面没写break,然后执行到其他case的情况)
2.go语言里面的case可以写判断条件(我记得java里面就是只能写个数字)
下面两段代码,看一下就行了
func main() {
fmt.Println("请输入你的年龄:")
var age int
fmt.Scan(&age)
switch {
case age <= 0:
fmt.Println("未出生")
case age <= 18:
fmt.Println("未成年")
case age <= 35:
fmt.Println("青年")
default:
fmt.Println("中年")
}
}
func main() {
fmt.Println("请输入星期数字:")
var week int
fmt.Scan(&week)
switch week {
case 1:
fmt.Println("周一")
case 2:
fmt.Println("周二")
case 3:
fmt.Println("周三")
case 4:
fmt.Println("周四")
case 5:
fmt.Println("周五")
case 6, 7:
fmt.Println("周末")
default:
fmt.Println("错误")
}
}
go语言里面的循环语句只有for语句,没有while语句。
go语言的理念里,认为for循环也可以实现while循环,所以就没有while循环
还有就是go语言里面也没有do while语句,但是也可以使用for循环来实现。
下面就是代码
//求100以内的和
//跟java,c是不是很像
//但我不知道为什么go语言不喜欢写括号
sum := 0
for i := 0; i <= 100; i++ {
fmt.Println(i)
sum += i
}
fmt.Println(sum)
//死循环
for i := 0; true; i++ {}
//这样写死循环也是可以的
for true{}
for {}
//go语言没有while循环,下面是go语言里面的while模式
var sum int
var i int = 1
for i <= 100 {
sum += i
i++
}
fmt.Println(sum)
//do while 模式
sum := 0
var i int = 1
for {
sum += i
i++
if i == 101 {
break
}
}
fmt.Println(sum)
//类似python一样的for循环
var list = []string{"枫枫", "知道"}
for index, item := range list {
fmt.Println(index, item)
}
go语言认为变量定义了就要使用,不然就会报错,你不使用这个变量就不要定义。但是我们必须要接收两个变量该怎么办呢?
可以使用下划线来代替这个变量,这个在go语言里面就可以理解为占位用的。比如下面这段代码
var list = []string{"枫枫", "知道"}
for _, item := range list {
fmt.Println(index, item)
}
在这段代码中,假如我不需要index,就可以写成下划线。
跟其他语言里面的作用是一模一样,没有要补充的
go语言里面的函数,我愿称之为抽象,我是真没见过如此抽象的东西,我都不知道这里能不能写清楚。
我在之前说go语言里面 if 和 for 循环不知道为什么不喜欢写括号,现在你会函数里面疯狂写括号
先来简单一点
func sayHello() {
fmt.Println("hello")
}
func param1(id string) {
fmt.Println(id)
}
func param2(id string, userName string) {
fmt.Println(id, userName)
}
// 当多个参数的数据类型相同的时候,写一个就行了
func param3(id, userName string) {
fmt.Println(id, userName)
}
类比python里面的不定长参数
// 没有确定长度的参数
func add(numerList ...int) {
var sum int
for _, i2 := range numerList {
sum += i2
}
fmt.Println(sum)
}
// 没有返回值的函数
func r1() {
// 没有返回值
return
}
func r2() bool {
return false
}
友友们,注意了,第一个括号来了,如果你想返回多个值,要加个括号。这里算是go语言的特性,我记得java基础里面函数是只能返回一个数据,python里面,虽然return可以返回多个变量,但是python会自动给你转成tuple类型,但是这里就真的是多个变量,你接收的时候也需要多个变量
// 有多个返回值的函数
func r3() (string, bool) {
return "", false
}
func main() {
a, b := r3()
fmt.Printf("%#v,%#v", a, b)
}
友友们还记得上面我们说的默认值吗?这里可以说是go语言的特性。
在返回值里定义了参数,然后直接写个return就会默认返回定义在返回值里面的数,我们也可以对返回值里的变量进行修改,那么,最后返回的时候,就是我们修改过的返回的变量。
func r4() (val string, ok bool) {
if true {
val = "12"
return
}
return
}
func main() {
a, b := r4()
fmt.Printf("%#v,%#v", a, b)
}
// 定义一个匿名函数并将其赋值给变量add
add := func(a, b int) int {
return a + b
}
// 调用匿名函数
result := add(3, 5)
fmt.Println("3 + 5 =", result)
go语言里面还可以将函数作为参数来进行传递。
注意,go语言里面不能写函数嵌套,但是我们可以将函数作为参数进行传递,来实现嵌套(其实还是匿名函数)
func awaitAdd(awaitSecond int) func(...int) int {
return func(numberList ...int) (sum int) {
for _, i2 := range numberList {
sum += i2
}
return sum
}
}
func getSequence() func() int {
i:=0
return func() int {
i+=1
return i
}
}
一句话就是,值传递相当于传递了变量的副本,函数内部是对变量的副本进行修改,不会对变量本身产生任何影响,引用传递就是把变量的指针给传递过去,这样函数内部的任何变化也会引起外部变量的修改。写法跟c语言是一模一样
package main
import "fmt"
func deliver(num int) int {
num += 1
return num
}
func deliver2(num *int) int {
*num += 1
return *num
}
func main() {
num := 1
fmt.Println("没有传递给deliver之前的值:", num)
fmt.Println("经过deliver之后的值", deliver(num))
fmt.Println("外面的值", num)
//&是取地址,*是解引用,去这个地址指向的值
fmt.Println("没有传递给deliver2之前的值:", num)
fmt.Println("经过deliver之后的值", deliver2(&num))
fmt.Println("外面的值", num)
}
看代码吧,简单说就是定义在任何函数之外的变量。
package main
//全局变量
var a int = 1
func main() {
//局部变量和
var b int = 1
}
在全局变量里面,使用const定义的常量 ,大写开头可以被其他go语言文件访问到,但是小写开头不行。
package version
const Version = "1.1.1.1"
说明一下,go语言不支持隐式转换类型,必须要写怎么转
var a int = 10
var b float64 = float64(a)
var str string = "10"
var num int
num, _ = strconv.Atoi(str)
num := 123
str := strconv.Itoa(num)
fmt.Printf("整数 %d 转换为字符串为:'%s'\n", num, str)
str := "3.14"
num, err := strconv.ParseFloat(str, 64)
if err != nil {
fmt.Println("转换错误:", err)
} else {
fmt.Printf("字符串 '%s' 转为浮点型为:%f\n", str, num)
}
num := 3.14
str := strconv.FormatFloat(num, 'f', 2, 64)
fmt.Printf("浮点数 %f 转为字符串为:'%s'\n", num, str)
到这里,go语言基础部分讲的差不多了,剩下的就是go语言的类似面向对象的东西(结构体,接口),异常处理,I/O操作,反射,泛型,协程,channel(特性)等东西了。后面我还会再写,今天再放在一起就太多了。然后,有什么问题可以提出来,博主看到后会马上修改。谢谢。
记得点个赞和收藏