极简Go语言教程

公众号:Hoeller

教程中涉及到Go的知识点有:安装、变量、常量、特殊常量iota、切片、结构体、函数、方法、接口、指针。

安装

安装地址:golang.google.cn/dl/,按操作系统选择安装包
image.png

配置环境变量

  • Windows将c:Gobin配置到Path环境变量中
  • Mac不需要额外配置
  • Linux将解压出来的目录中的bin目录配置到Path环境变量中
  • 验证版本

    在命令行执行go version输出版本则表示安装成功

    dadudu@dadududeMBP ~ % go version
    go version go1.21.3 darwin/arm64

    Hello World

    在任意地方新建文件hello.go,内容为

    package main
    import "fmt"
    func main() {
    fmt.Println("Hello, World")
    }

    然后运行go run hello.go即可得到输出结果:"Hello, World"。

    变量

    go里面用var来定义变量,名字在前,类型在后,并且可以一次定义多个变量

    package main
    import "fmt"
    func main() {
    var a string = "dadudu"
    var b, c int = 1, 2
    fmt.Println(a,b,c)
    }

    类型推导

    也可以直接不写类型,go会根据值自动推导出变量的类型

    var a = "dadudu"
    var b, c = 1, 2

    :=定义变量

    因为有了类型推导,所以var关键字也可以不写,使用:=来定义变量并赋值

    package main
    import "fmt"
    func main() {
    a := "dadudu"
    b, c := 1, 2
    fmt.Println(a, b, c)
    }

    修改变量

    变量是可以修改的,直接用=给变量赋不同的值就可以了

    a = "xiaodudu"
    

    注意:=是用来定义变量的,不能用来修改变量。

    常量

    常量就是定义并初始化后就不能修改了,语法上跟变量一样,只是关键字用const

    package main
    import "fmt"
    func main() {
    const a = "dadudu"
    //a = "xiaodudu" 此处编译报错
    fmt.Println(a)
    }

    也可以一次性定义多个常量:

    func main() {
    const a, b, c = "dadudu", 1, 2
    fmt.Println(a, b, c)
    }

    但是const关键字不能省略,不然就成了变量,但是如果确实有多个常量需要定义,或者定义枚举,还可以这样写

    func main() {
    const (
    creating = 0
    created = 1
    unpaid = 2
    paid = 3
    )
    fmt.Println(creating, created, unpaid, paid)
    }

    输出结果为:0 1 2 3

    特殊常量iota

    以上代码可以简化为:

    func main() {
    const (
    creating = iota
    created
    unpaid
    paid
    )
    fmt.Println(creating, created, unpaid, paid)
    }

    输出结果同样为:0 1 2 3,赋值了iota的常量的值是0,后续的常量会自动加1,如果在四个常量中间新增了常量,那么五个常量的值会自动改变:

    func main() {
    const (
    creating = iota
    created
    createFailed // 新增
    unpaid
    paid
    )
    fmt.Println(creating, created, createFailed, unpaid, paid)
    }

    输出结果为:0 1 2 3 4,这样就能省掉程序员手动调整常量值的麻烦(想想Java中要怎么做....)

    切片

    go里有数值和切片两种类型,分别是这么定义的:

    func main() {
    a := [5]int{1, 2, 3, 4, 5} // 数组
    b := []int{1, 2, 3, 4, 5} // 切片
    fmt.Println(a, b)
    }

    数组长度不可变,切片长度可变,所以切片也叫做动态数组。

    比如,可以给切片添加元素:

    func main() {
    a := [5]int{1, 2, 3, 4, 5} // 数组
    b := []int{1, 2, 3, 4, 5} // 切片
    b = append(b, 6)
    fmt.Println(a, b)
    }

    输出结果为:

    [1 2 3 4 5]
    [1 2 3 4 5 6]

    切片没有直接提供remove方法,可以通过append方法间接删除,以下代码会删除掉切片中下标为1的元素(2):

    func main() {
    a := [5]int{1, 2, 3, 4, 5} // 数组
    b := []int{1, 2, 3, 4, 5} // 切片
    b = append(b[:1], b[2:]...)
    fmt.Println(a, b)
    }

    输出结果为:

    [1 2 3 4 5]
    [1 3 4 5]

    另外,数组和切面都可以截取范围来访问元素:

    func main() {
    a := [5]int{1, 2, 3, 4, 5} // 数组
    b := []int{1, 2, 3, 4, 5} // 切片
    fmt.Println(a[1:4], b[2:5])
    }

    输出结果为:

    [2 3 4]
    [3 4 5]

    结构体

    如果你想要有一个“对象”,那么就可以定义一个结构体并构造出“对象”:

    type User struct {
    id int
    name string
    age int
    }
    func main() {
    // 创建User对象
    user := User{1, "dadudu", 18}
    // 输出对象的name属性
    fmt.Println(user.name)
    }

    函数与方法

    Java只有方法,要么是静态方法(归属于类),要么是普通方法(归属于对象),go中分为函数与方法。

    type User struct {
    id int
    name string
    age int
    }
    func getNameAndAge(user User) (string, int) {
    return user.name, user.age
    }
    func main() {
    // 创建User对象
    user := User{1, "dadudu", 18}
    name, age := getNameAndAge(user)
    fmt.Println(name, age)
    }

    以上getNameAndAge就是一个函数,接收一个User类型对象,返回一个string和一个int,有点类似于Java的静态方法,不需要生成对象才能调用,直接调就可以了,但是强大的地方在于,一个函数可以有多个返回值(这个是真好用...)。

    以下代码中的getNameAndId就是一个方法,并且该方法跟User结构体绑定在一起了,而函数是没有和某个结构体绑定的,调用方法就需要对象才能调用

    // 函数
    func getNameAndAge(user User) (string, int) {
    return user.name, user.age
    }
    // 方法
    func (user User) getNameAndId() (string, int) {
    return user.name, user.id
    }
    func main() {
    // 创建User对象
    user := User{1, "dadudu", 18}
    name, age := getNameAndAge(user)
    name, id := user.getNameAndId()
    fmt.Println(id, name, age)
    }

    接口

    Java中,需要在代码中先实现接口,然后必须实现接口中的方法,而在go中,一个结构体只要实现了某个接口的所有方法,那么这个结构体就是这个接口的“实现类”。

    type Person interface {
    getName() string
    getAge() int
    }
    type User struct {
    id int
    name string
    age int
    }
    func (user User) getName() string {
    return user.name
    }
    func (user User) getAge() int {
    return user.age
    }
    func main() {
    var person Person = User{1, "dadudu", 18} // 赋值语句
    fmt.Println(person)
    }

    以上代码中,由于给User结构体绑定了getName()getAge()方法,所以User实现了Person接口中的两个方法,也就相当于User实现了Person接口,所以可以把User对象直接赋值给Person类型的变量。但凡注释掉其中一个方法,赋值语句都将报错。

    指针

    变量表示值,而指针表示值所在的内存地址,其实就是跟Java中的值传递和引用传递类似,比如以下代码:

    func test(a int) {
    a = 2
    }
    func main() {
    a := 1
    test(a) // 修改了a的值
    fmt.Println(a)
    }

    最终输出的的a为1,虽然test函数中修改了a的值,但由于是指传递,传递给test函数的是一个副本,所以原本的a并没有发生改变。

    而一旦把代码改成:

    func test(a *int) {
    *a = 2 // 将指针位置的值改为2
    }
    func main() {
    a := 1
    test(&a) // 传入a的指针
    fmt.Println(a)
    }

    输出的a就是2了,因为传给test函数是a的指针,并且test函数中会把指针位置的值改为2。

    极简Go教程就到这啦,大家如果觉得这种极简风格还可以,还想看其他语言的,记得点赞、收藏、分享告诉我哦~

    欢迎大家关注我的公众号:Hoeller,第一时间接收我的原创技术文章,你将收获更多干货知识。