【Go】操作手册

main

main包具有特殊含义,Go编译器识别main包,并执行底下的main函数,将其编译为二进制可执行文件。

main作为主函数,每个代码文件中的init函数都会在main函数执行前调用。

import

import (
    "fmt"
    "log"

    _ "github.com/goinaction/code/chapter2/sample/matchers"
    "github.com/goinaction/code/chapter2/sample/search"

)

下划线代表别名,因为Go不允许代码文件里存在未使用的import,使用_忽视这个规则,可以调用引入库的init方法。

for

支持range,每次迭代返回两个值,第一个是迭代的元素在切片里的索引位置,第二个值是元素值的一个副本。示例:

for _, feed := range feeds {
    ...
}
for index := 2; index < len(slice); index++ {
    fmt.Printf("Index: %d" Value: %d\n", index, slice[index])
}

内置函数len返回长度,cap返回容量

struct

type Feed struct {
    Name string `json:"site"`
    URI string `json:"link"`
    Type string `json:"type"`
}

`引号里的部分被称作标记(tag),描述了json阶码的元数据,将结构类型的字段与json里指定的字段一一对应,同样也可以匹配于别的数据源。

interface

type Matcher interface {
    Search(feed *Feed, searchTerm string) ([]*Result, error)
}

接口的行为最终由在这个接口类型中声明的方法决定。Go的命名惯例:单个方法的接口名以er结尾。

实现接口:

type defaultMatcher struct{}

func init() {
    var matcher defaultMatcher
    Register("default", matcher)
}

func (m defaultMatcher) Search(feed *Feed, searchTerm string) ([]*Result, error) {
    return nil, nil
}
func (m defaultMatcher) Search

这行代码代表Search函数带有接收者,即指定defaultMatcher类型。接收者既可以是类型值,也可以是指向这个类型值的指针。最佳实践是将方法的接收者声明为指针。当方法接收者设置为指针类型,那么当接口类型的值调用方法时,只有指针能够调用。如果发放的接收者设置为值类型,那么没有这个限制。

defer

defer关键字会安排随后的函数调用在函数返回时才执行,即使函数意外崩溃终止,也能保证defer后的函数被执行。

defer file.Close()

变量声明

var matchers = make(map[string]Matcher)

var关键字声明变量,表明matchers是一个以string为key,Matcher为value的map。使用make来构造map,因为map是一种引用类型,默认的零值是nil。其他的引用类型还有channel、slice、interface以及函数类型。

变量声明也可以用简化的声明运算符:=,比如:

feeds, err := RetrieveFeeds()

一般来说,如果需要声明初始值为零值的变量,应该使用var来声明变量;如果有确切的初始值或函数返回值,那么用简化变量声明运算符。

变量名以小写字母开头表明是包内使用的变量,以大写开头则对外开放。

默认初始值

在Go中,所有变量都被初始化为零值。数值->0,字符串->"",布尔->false,指针->nil。

Go中支持数组的切片。

Go中所有的参数传递都是值传递。

数组

声明

var array [5]int

 声明并初始化

array := [5]int{10, 20, 30, 40, 50}
array := [...]int{10, 20, 30, 40, 50}

...让Go自动统计元素数。

​array := [5]*int{0: new(int), 1: new(int)}

​
*array[0] = 10
*array[1] = 20

整型指针数组,为数组前两个元素赋值。

var array2 [5]int

array2 = array

Go的数组可以通过赋值直接复制另一个数组的值,但前提是两个数组的长度和类型必须相同。

var array[4][2]int

array := [4][2]int{{10,11}, {20,21}, {30,31}, {40,41}}

二维数组

切片slice

与数组不同,切片是一种引用类型,容量是切片内元素允许增长到最大的值。当不指定[ ]运算符里的值时,创建的才是切片,否则是数组。切片的底层是数组,它的指针指向数组元素。

// 切片容量和长度都是5
slice := make([]string, 5)


// 切片容量为5,长度为3
slice := make([]string, 3, 5)

// 基于初始化时提供的元素确定容量
slice := []string{"Red", "Blue", "Green"}

// 空切片
slice := make([]int, 0)
// or
slice := []int{}

// 切片
newSlice := slice[1:3]
// append
newSlice = append(newSlice, 60)

由于切片是引用类型,关联数据保存在底层数组,所以在传递切片时所占用的内存很小,不需要传递指针。

 

映射map

// 创建map
dict := make(map[string]int)

dict := map[string]string{"Red": "#da1337", "Orange": "#e95a22"}
matcher, exists := matchers[feed.Type]
if !exists {
    matcher = matchers["default"]
}

迭代map

for key, value := range colors {
    fmt.Printf("Key: %s Value: %s\n", key, value)
}

删除

delete(colors, "Red")

map的底层同样是数组。map也是引用类型。

赋值给两个变量,第一个变量和赋值给一个变量一样,都是map查找的结果。如果有第二个值,它表示的是查找的键是否在map里,是一个布尔值。

 

用户自定义类型

type user struct {
    name     string
    email     string
}

lisa := user{
    name:    "Lisa",
    email:    "[email protected]",
}

// 对顺序有要求的方式
lisa := user{"Lisa", "[email protected]"}

嵌套定义

type admin struct {
    person user
    level string
}

fred := admin{
    person: user{
        name:    "Lisa",
        email:    "[email protected]",
    },
    level: "super",
}

编译器只允许为命名的用户定义的类型声明方法,比如:

type IP []byte

func (ip IP) MarshalText() ([]byte, error) {
    ...
}

内部类型实现接口,会提升至外部类型同样实现这个接口。比如user实现了某个接口,那么也会认为admin也实现了此接口,在参数传递时可以接收user实现接口的函数同样会接受admin结构。如果想实现内部类型和外部类型的多态,那么需要让外部类型也作为接收者实现接口。

goroutine

Go的并发同步模型源于通信顺序进程CSP的泛型,这是一种消息传递模型,通过在goroutine之间传递数据来传递消息,而不是对数据进行加锁来实现同步访问。goroutine之间同步和传递的关键数据类型叫做通道channel。goroutine

go func(matcher Matcher, feed *Feed) {
    Match(matcher, feed, searchTerm, results)
    waitGroup.Done()
}(matcher, feed)

所有的goroutine都会因为闭包共享外层变量。

goroutine间可以通过指针共享数据

使用goroutine的最佳实践之一:在main函数返回前,清理并终止所有之前启动的goroutine。

可以使用sync包的WaitGroup来跟踪goroutine的工作是否完成,WaitGroup是一个计数信号量,使用方法如下:

var waitGroup sync.WaitGroup

waitGroup.Add(len(feeds))

使用它的Add函数来设定将要启动的goroutine的数量,使用Done函数来表示当前goroutine执行完成。

你可能感兴趣的:(面试)