初识go语言 | 青训营笔记

98 阅读7分钟

这是我参与[第五届青训营]伴学笔记创作活动的第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博客 有比较详细的注释,课程理解不了的内容就看这里

边看春晚边学Go| 青训营笔记 - 掘金 (juejin.cn)