Image Description

七、字典/映射(map)

map 是一种键值对的无序集合,与 slice 类似也是一个引用类型。map 本身其实是个指针,指向内存中的某个空间。

声明方式与数组类似,声明方式:var 变量名 map [key类型] 值类型 或直接使用 make 函数初始化:make( map [key类型] 值类型, 初始空间大小)

其中 key 值可以是任何可以用==判断的值类型,对应的值类型没有要求。

package main

import (
    "fmt"
    "unsafe"
)

func main() {

    //声明后赋值
    var m map[int]string
    fmt.Println(m)       //输出空的map:map[]
    
    //声明并用{}或make初始化,
    var m1 = map[string]int{}
    var m2 = make(map[string]int)

    m1[`a`] = 11
    m2[`b`] = 22
    fmt.Println(m1)     //输出:map[a:11]
    fmt.Println(m2)     //输出:map[b:22]

    //初始化多个值
    var m3 = map[string]string{"a": "aaa", "b": "bbb"}
    m3["c"] = "ccc"
    fmt.Println(m3)

    //删除 map 中的值
    delete(m3, "a")
    fmt.Println(m3)

    //查找 map 中的元素
    v, ok := m3["b"]
    if ok {
      fmt.Println(ok)
      fmt.Println("m3中b的值为:", v)
    }

    if v, ok := m3["b"]; ok {
      fmt.Println("m3中b的值为:", v)
    }

    fmt.Println(m3["c"])

    //map中的值可以是任意类型
    m4 := make(map[string][5]int)
    m4["a"] = [5]int{1, 2, 3, 4, 5}
    m4["b"] = [5]int{11, 22, 33}

    fmt.Println(m4)                  
    fmt.Println(unsafe.Sizeof(m4))
}

八、通道(channel)

Channel 是 Go中的一个核心类型,你可以把它看成一个管道,通过它并发核心单元就可以发送或者接收数据进行通讯 ( communication )。

说到通道 channel,则必须先了解下 Go 语言的 goroutine 协程(轻量级线程)。channel 就是为 goroutine 间通信提供通道。goroutine 是 Go 语言提供的语言级的协程,是对 CPU 线程和调度器的一套封装。

channel 也是类型相关的,一个 channel 只能传递一种类型的值。

声明:var 通道名 chan 通道传递值类型 或 make 函数初始化:make(chan 值类型, 初始存储空间大小)

package main

import (
  "fmt"
  "time"
)

func main() {
    
    var ch1 chan int              //声明一个通道
    ch1 = make(chan int)          //未初始化的通道不能存储数据,初始化一个通道
    ch2 := make(chan string, 2)   //声明并初始化一个带缓冲空间的通道
    
    //通过匿名函数向通道中写入数据,通过 <- 方式写入
    go func() { ch1 <- 1 }()
    go func() { ch2 <- `a` }()
    
    v1 := <-ch1         //从通道中读取数据
    v2 := <-ch2
    fmt.Println(v1)     //输出:1
    fmt.Println(v2)     //输出:a

    //写入,读取通道数据
    ch3 := make(chan int, 1)   //初始化一个带缓冲空间的通道
    go readFromChannel(ch3)
    go writeToChannel(ch3)

    // 线程休眠1秒,让出执行权限给子 Go 程,即通过 go开启的goroutine,不然主程序会直接结束
    time.Sleep(1 * time.Second)
}

func writeToChannel(ch chan int) {
  for i := 1; i < 10; i++ {
    fmt.Println("写入:", i)
      ch <- i
  }
}

func readFromChannel(ch chan int) {
  for i := 1; i < 10; i++ {
    v := <-ch
    fmt.Println("读取:", v)
  }
}

九、结构体(struct)

结构体是一种聚合的数据类型,是由零个或多个任意类型的值聚合成的实体。每个值称为结构体的成员。

package main

import "fmt"

//定义一个结构体 person
type person struct {
    name string
    age  int
}

func main() {

    var p person   //声明一个 person 类型变量 p
    p.name = "max" //赋值
    p.age = 12

    fmt.Println(p) //输出:{max 12}
    p1 := person{name: "mike", age: 10} //直接初始化一个 person

    fmt.Println(p1.name)                //输出:mike

    p2 := new(person) //new函数分配一个指针,指向 person 类型数据
    p2.name = `张三`
    p2.age = 15
    fmt.Println(*p2) //输出:{张三 15}
}

十、接口(interface)

接口用来定义行为。Go 语言不同于面向对象语言,没有类的概念,也没有传统意义上的继承。

Go 语言中的接口,用来定义一个或一组行为,某些对象实现了接口定义的行为,则称这些对象实现了(implement)该接口,类型即为该接口类型。

定义接口也是使用 type 关键字,格式为:

//定义一个接口
type InterfaceName interface {
    FuncName1(paramList) returnType
    FuncName2(paramList) returnType
    ...
}

实例

package main

import (
    "fmt"
    "strconv"
)

//定义一个 Person接口
type Person interface {
    Say(s string) string
    Walk(s string) string
}

//定义一个 Man结构体
type Man struct {
    Name string
    Age  int
}

//Man 实现 Say 方法
func (m Man) Say(s string) string {
  return s + ", my name is " + m.Name
}

//Man 实现 Walk方法
func (m Man) Walk(s string) string {
  return "Age: " + strconv.Itoa(m.Age) + " and " + s
}

func main() {

    //声明一个类型为 Man 的变量
    var m Man
    m.Name = "Mike"
    m.Age = 30

    fmt.Println(m.Say("hello"))
    fmt.Println(m.Walk("go work"))

    jack := Man{Name: "jack", Age: 25}

    fmt.Println(jack.Age)
    fmt.Println(jack.Say("hi"))        
}

十一、错误(error)

error 类型本身是 Go 语言内部定义好的一个接口,接口里定义了一个 Error() 打印错误信息的方法,源码如下:

type error interface {
    Error() string
}

自定义错误信息:

package main

import (
    "errors"
    "fmt"
)

func main() {
    
    //使用 errors 定制错误信息
    var e error
    e = errors.New("This is a test error")
    fmt.Println(e.Error()) //输出:This is a test error

    //使用 fmt.Errorf() 定制错误信息
    err := fmt.Errorf("This is another error")
    fmt.Println(err) // 输出:This is another test error
}