这是我参与[第五届青训营]伴学笔记创作活动的第1天
背景介绍
什么是go语言可以不用过多介绍
为什么要使用go语言?
因为go语言语法简单,开发效率和性能比较高
因为初学嘛,我按照自己的理解写的比较简单,实际肯定还有其他很多优点
开发环境
go安装包下载
下载地址:Go下载 - Go语言中文网 - Golang中文社区 (studygolang.com)
进入网址后:下载推荐的即可
编辑器
编辑器以下三个选择一个皆可
-
VsCode(需要安装Go插件)
-
Golang
-
IDEA
开始本来想使用Golang,但是下载下来发现要收费,最后还是选择使用VsCode
文件
main.go
package main
//引入的函数
import (
"fmt"
)
func main() {
fmt.Println("hello world")
}
通过终端输入go run main.go来运行
从这个最简单的版本,我们就知道写一个go程度需要三个部分
- 导包
- 引入函数
- main方法里面写逻辑
基础语法
变量
声明变量的两种方式
var 变量名 (显示指定变量类型) = 值;
变量名 := 变量值;
声明常量
const 常量名=值
if else
func main() {
//在条件语句之前可以有一个声明语句,在这里声明的表明可以用于所有的条件分支
if num:=9 ;num < 0{
fmt.Println(num,"is negative")
}else if num < 10{
fmt.Println(num,"has 1 digit")
}else{
fmt.Println(num,"has multiple digits")
}
}
【注意】这个声明的表明不能用于外面,在if里面定义的变量相当于内部变量
输出结果为
9 has 1 digit
循环
在go语言中,使用for就能表示java中的while以及for循环,具体可以看一下go语言中表示循环的三种方式
//一般的for循环
for j:=1 ;j < 3;j++{
fmt.Println(j)
}
//while循环
for {
fmt.Println("进入了死循环")
}
//第三种形式
var j = 1
for j<3 {
fmt.Println(j)
j= j+1;
}
【注意】(1)循环开始的值写成变量 := 起始值不要写错了(2)对于第三种形式是需要提前定义好变量的
switch
switch的两种写法,我自己取名为等值判断写法和非等值判断写法
package main
import (
"fmt"
"time"
)
func main() {
//第一种写法(等值判断)
i := 1
switch i{
case 1:fmt.Println("one")
case 2:fmt.Println("two")
default:fmt.Println("qita")
}
//第二种写法(非等值判断)
h := time.Now()
switch {
case h.Hour() < 12: fmt.Println("现在是上午")
default:fmt.Println("现在是下午")
}
}
输出结果为
one
现在是下午
数组
定义数组的两种方式
//定义了一个长度为5的数组,如果不指定值则会有默认值
var a [5]int
a[0] = 100
fmt.Println(a[0])
fmt.Println(a[4])
fmt.Println(len(a))
//定义的时候就指定具体的值
b := [(5)]int{1,2,3,4,5}
fmt.Println(b)
fmt.Println(b[1])
输出结果为
100
0
5
[1 2 3 4 5]
2
切片
切片不同于数组,可以进行切分等各种丰富的操作
//切片定义
s := make([]string,3)
s[0] = "a"
s[1] = "b"
s[2] = "c"
//切片进行拼接
s = append(s,"d")
s = append(s,"e","f")
c := make([]string,len(s))
//切片复制
copy(c,s)
fmt.Println(c)
//切片截取
fmt.Println(c[2:5])
fmt.Println(c[2:])
fmt.Println(c[:5])
输出结果
[a b c d e f]
[c d e]
[c d e f]
[a b c d e]
【注意】
(1)通过make(类型,长度)来创建切片
(2)copy(c,s)表示将s拷贝给c,如果交换顺序,则返回值全为空
(3) c[2:5]是下标的左闭右开区间,表示下标2到5的元素,包含2但是不包含5
map
可以定义一个空的map也可以定义的时候直接赋值
//使用make创建一个空map
m := make(map[string]int)
m["one"] = 1
m["two"] = 2
fmt.Println(m["unknown"]) //0
r,ok := m["unknown"]
//这个是什么东西?
fmt.Println(r,ok) //0 ,false
//删除m中key为"one"的键值对
delete(m,"one")
//直接创建一个带有键值对的map
m2 := map[string]int{"one":1,"two":2}
var m3 = map[string]int{"one":1,"two":2}
fmt.Println(m2,m3)
输出结果
0
0 false
map[one:1 two:2] map[one:1 two:2]
【问题】在课程中下面这两行代码没有理解
r,ok := m["unknown"]
fmt.Println(r,ok) //0 ,false
range
通过range实现map和数组的遍历
//遍历map
m := map[string]string{"a":"A","b":"B"}
for _,v:=range m{
fmt.Println(v)
}
//遍历数组
nums := []int{1,2,3,4,5}
for index,num := range nums{
fmt.Println(index,num)
}
【注意】对于数组第一个值是下标,第二值是值。如果不需要下标可以用下划线来忽略
同理map第一个值是key,第二个值是value,如果不需要key同样可以用下划线你来忽略
小tips:map是无序的,所以拿出来的键值对是随机的
函数
学习go语言的函数我发现了和java的亮点不同
- go语言变量类型后置,java是前置
- go语言可以返回一个值,也可以返回两个值;java只能返回一个值
//返回一个值
func add(a int,b int) int {
return a+b
}
//返回两个值
func exists(m map[string]string, k string) (v string, ok bool) {
v, ok = m[k]
return v, ok
}
func main() {
调用函数即可
}
对于返回两个值还有一种写法
func exists(m int, k int) ( int, int) {
m = 3
k = 7
return m, k
}
区别在于如果返回的两个函数没有给具体的变量名,那么在函数内部无法使用,只需要返回要求的类型即可;给了具体的变量名,那么可以在内部使用``
相同在于返回类型要与指定的类型一致;返回的值是多少就是多少
【问题】不是很理解,和课件代码一样还能报错
问题找到了:这个函数不能定义在main方法里面
指针
指针有什么用?
我们都知道go语言是值传递的。
因此,我们试图把变量增加,但是增加是调用函数后,在函数里面完成的,在函数外面是不生效的,因此为了满足这种需求
我们使用指针来完成,可能解释得不够好,但是下面这个代码的输出就能帮助我们理解
func add2(n int) {
n += 2
}
func add2ptr(n *int) {
*n += 2
}
func main() {
n := 5
fmt.Println(n) // 5
add2ptr(&n)
fmt.Println(n) // 7
}
【注意】使用指针除了在函数形参里面加*,还要在调用函数时,实参前面加&
结构体
结构体可以包含多个字段,通过结构体的名称去初始化一个结构体变量
type user struct {
name string
password string
}
func main() {
a := user{ name: "wang", password: "1024"}
b := user{"wang", "1024"}
update(&a)
fmt.Println(a.password)
update1(b)
fmt.Println(b.password)
}
func update(u *user) bool{
u.password = "limingjie"
return true
}
func update1 (u user) bool{
u.password ="limingjie"
return false
}
输出以下
limingjie
1024
从输出不难看出,结构体也支持指针,能够实现结构体的修改
结构体方法
定义结构体方法是定义函数的前面加上结构体
结构体和函数内的参数都作为形参
type user struct {
name string
password string
}
func main() {
a := user{name:"wang",password:"1024"}
a.resetPassword("limingjie")
fmt.Println(a.checkPassword("limingjie"))
}
func (u user) checkPassword(password string) bool {
return u.password == password
}
func (u *user) resetPassword(password string) {
u.password = password
}
返回值
true
【注意】如果去掉在定义结构体方法时去掉*,相当于去掉指针,则不会修改结构体
错误
不出现错误则返回nil 出现错误则返回errors(需要引入函数)
func findUser(users []user, name string) (v *user, err error) {
for _, u := range users {
if u.name == name {
return &u, nil
}
}
return nil, errors.New("not found")
}
【问题】返回值加指针有啥用?
标准库
go语言和java类似提供了丰富的标准库工具可以用于做字符串操作、字符串格式化、json处理以及时间处理
这里就不过多展示了,知道有哪些用处即可,到时候根据需求即查即用即可
总结与反思
本节笔记主要做了以下记录
- 简单了解go的背景以及go的优势
- 掌握了go的开发环境,主要就是go安装包以及编辑器的下载
- 熟悉go的基本语法和丰富的标准库
不足:我在学习过程中,试图一次吃透语法,导致总是卡在某一个环节很长时间,事后来看,这浪费大量时间并且消耗了巨大精力
解决方案:拒绝完美主义,在实践中不断运用这些语法,从而实现自然的长期记忆
参考
走进 Go 语言基础语言 - 掘金 (juejin.cn) 字节跳动内部课:视频分为30分钟简单了解语法以及40分钟小项目实践 【后端专场 学习资料一】第五届字节跳动青训营 - 掘金 (juejin.cn) 里面含有课程当天,课前、中、后的学习内容
通过例子学习golang语言基础(一)_weixin_43764107的博客-CSDN博客 有比较详细的注释,课程理解不了的内容就看这里