Go 语言基础 2 | 青训营笔记

57 阅读5分钟

Go 语言基础

这是我参与「第五届青训营 」伴学笔记创作活动的第 2 天

2 入门

2.7 基础语法 - map

下面介绍 map,在其他编程语言里面,它可能可以叫做哈希或者字典。map 是实际使用过程中最频繁用到的数据结构。 我们可以用 make 来创建一个空 map,这里会需要两个类型,第一个是那个 key 的类型,这里是 string 另一个是 value 的类型,这里是 int。我们可以从里面去存储或者取出键值对。可以用 delete 从里面删除键值对。

golang 的 map 是完全无序的,遍历的时候不会按照字母顺序,也不会按照插入顺序输出,而是随机顺序。

package main

import "fmt"

func main() {
	m := make(map[string]int)
	m["one"] = 1
	m["two"] = 2
	fmt.Println(m)           // map[one:1 two:2]
	fmt.Println(len(m))      // 2
	fmt.Println(m["one"])    // 1
	fmt.Println(m["unknow"]) // 0

	r, ok := m["unknow"]
	fmt.Println(r, ok) // 0 false

	delete(m, "one")

	m2 := map[string]int{"one": 1, "two": 2}
	var m3 = map[string]int{"one": 1, "two": 2}
	fmt.Println(m2, m3)
}

2.8 基础语法 - range

下面来介绍 range。对于一个 slice 或者一个 map 的话,我们可以用 range来快速遍历,这样代码能够更加简洁。range 遍历的时候,对于数组会返回两个值,第一个是索引, 第二个是对应位置的值。如果我们不需要索引的话,我们可以用下划线来忽略。

package main

import "fmt"

func main() {
	nums := []int{2, 3, 4}
	sum := 0
	for i, num := range nums {
		sum += num
		if num == 2 {
			fmt.Println("index:", i, "num:", num) // index: 0 num: 2
		}
	}
	fmt.Println(sum) // 9

	m := map[string]string{"a": "A", "b": "B"}
	for k, v := range m {
		fmt.Println(k, v) // b 8; a A
	}
	for k := range m {
		fmt.Println("key", k) // key a; key b
	}
}

2.9 基础语法 - 函数

这个是 Golang 里面一个简单的实现两个变量相加的函数。Golang 和其他很多语言不一样的是,变量类型是后置的。

Golang 里面的函数原生支持返回多个值。在实际的业务逻辑代码里面几乎所有的函数都返回两个值,第一个是真正的返回结果,第二个值是一个错误信息。

package main

import "fmt"

func add(a int, b int) int {
	return a + b
}

func add2(a, 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() {
	res := add(1, 2)
	fmt.Println(res) // 3

	v, ok := exists(map[string]string{"a": "A"}, "a")
	fmt.Println(v, ok) // A True
}

2.10 基础语法 - 指针

go 里面也支持指针。当然,相比 C 和 C++ 里面的指针,支持的操作很有限。指针的一个主要用途就是对于传入参数进行修改。 我们来看这个函数。这个函数试图把一个变量加 2。但是单纯像上面这种写法其实是无效的。因为传入函数的参数实际上是一个拷贝,那也说这个加 2,是对那个拷贝进行了加 2,并不起作用 。

如果我们需要起作用的话,那么我们需要把那个类型写成指针类型,那么为了类型匹配,调用的时候会加一个 & 符号。

package main

import "fmt"

func add2(n int) {
	n += 2
}

func add2ptr(n *int) {
	*n += 2
}

func main() {
	n := 5
	add2(n)
	fmt.Println(n) // 5
	add2ptr(&n)
	fmt.Println(n) // 7
}

2.11 基础语法 - 结构体

下面能介绍结构体。结构体的话是带类型的字段的集合。 比如这里 use r结构包含了两个字段,name 和 password。我们可以用结构体的名称去初始化一个结构体变量,构造的时候需要传入每个字段的初始值。也可以用这种键值对的方式去指定初始值,这样可以只对一部分字段进行初始化。同样的结构体我们也能支持指针,这样能够实现对于结构体的修改,也可以在某些情况下避免-些大结构体的拷贝开销。

package main

import "fmt"

type user struct {
	name     string
	password string
}

func main() {
	a := user{name: "wang", password: "1024"}
	b := user{"wang", "1024"}
	c := user{name: "wang"}
	c.password = "1024"
	var d user
	d.name = "wang"
	d.password = "1024"

	fmt.Println(a, b, c, d)                 // {wang 1024} {wang 1024} {wang 1024} {wang 1024}
	fmt.Println(checkPassword(a, "haha"))   // false
	fmt.Println(checkPassword2(&a, "haha")) // false
}

func checkPassword(u user, password string) bool {
	return u.password == password
}

func checkPassword2(u *user, password string) bool {
	return u.password == password
}

2.12 基础语法 - 结构体方法

在 Golang 里面可以为结构体去定义一些方法。会有一点类似其他语言里面的类成员函数。比如这里,我们把上面一个例子的 checkPassword 的实现,从一个普通函数,改成了结构体方法。这样用户可以像a.checkPassword("xx") 这样去调用。具体的代码修改,就是把第一个 参数,加上括号,写到函数名称前面。

在实现结构体的方法的时候也有两种写法,一种是带指针,一种是不带指针。这个它们的区别的话是说如果你带指针的话,那你那么你就可以对这个结构体去做修改。如果你不带指针的话,那你实际上操作的是一个拷贝,你就无法对结构体进行修改。

package main

import "fmt"

type user struct {
	name     string
	password string
}

func (u user) checkPassword(password string) bool {
	return u.password == password
}

func (u *user) resetPassword(password string) {
	u.password = password
}

func main() {
	a := user{name: "wang", password: "1024"}
	a.resetPassword("2048")
	fmt.Println(a.checkPassword("2048")) // true
}

2.13 基础语法 - 错误处理

错误处理在 go 语言里面符合语言习惯的做法就是使用一个单独的返回值来传递错误信息。不同于 Java 使用的异常。go 语言的处理方式,能够很清晰地知道哪个函数返回了错误,并且能用简单的 if else 来处理错误。

在函数里面,我们可以在那个函数的返回值类型里面,后面加一个 error,就代表这 个函数可能会返回错误。那么在函数实现的时候,return 需要同时 return 两个值,要么就是如果出现错误的话,那么可以 return nil 和一个error。如果没有的话,那么返回原本的结果和 nil。

package main

import (
	"errors"
	"fmt"
)

type user struct {
	name     string
	password string
}

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")
}

func main() {
	u, err := findUser([]user{{"wang", "1024"}}, "wang")
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(u.name) // wang

	if u, err := findUser([]user{{"wang", "1024"}}, "li"); err != nil {
		fmt.Println(err) // not found
		return
	} else {
		fmt.Println(u.name)
        }
}