Go语言学习六

164 阅读4分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

到了这一个环节,整个Go的基础入门就告一段落了,了解了Go的基本数据类型和相关语法,后面就是基础篇了

Go语言的接口

//无参数的接口实现
package main

import "fmt"

type Phone interface {
   call()
}

type NokiaPhone struct {
   //
}

func (np NokiaPhone) call() {
   fmt.Println("I am Nokia, I can call your family")
}

type Iphone struct {
   //
}

func (ip Iphone) call() {
   fmt.Println("I am Iphone, I can eat Japan")
}

func main() {
   /*
      接口:把所有具有共性的方法定义在一起,任何其他类型只要
      实现了这些方法就是实现了这个接口
   */

   var p Phone
   p = new(NokiaPhone)
   p.call()

   p = new(Iphone)
   p.call()

}
//带参数的接口实现
package main

import "fmt"

type Animal interface {
   eat()
}

type Cat struct {
   name string
}

func (cat Cat) eat() {
   fmt.Println(cat.name + "猫吃东西")
}

type Dog struct{}

func (dog Dog) eat() {
   fmt.Println("狗吃东西")
}
func main() {
   var animal1 Animal = Cat{"Tom"}
   var animal2 Animal = Dog{}
   animal1.eat()
   animal2.eat()
}

Go语言的错误处理

package main

import "fmt"

/*
 1、panic 在没有用 recover 前以及在 recover 捕获那一级函数栈,panic 之后的代码均不会执行;一旦被 recover 捕获后,外层的函数栈代码恢复正常,所有代码均会得到执行;
 2、panic 后,不再执行后面的代码,立即按照逆序执行 defer,并逐级往外层函数栈扩散;defer 就类似 finally;
 3、利用 recover 捕获 panic 时,defer 需要再 panic 之前声明,否则由于 panic 之后的代码得不到执行,因此也无法 recover;
 */

//实现

func main() {
   fmt.Println("外层开始")
   defer func() {
      fmt.Println("外层准备recove")
      if err := recover(); err != nil {
         //err已在上一级函数中被捕获,这里没有异常
         fmt.Printf("%#v-%#v\n", "外层", err)
      } else {
         fmt.Println("外层啥也没做")
      }
      fmt.Println("外层完成recover")
   }()
   fmt.Println("外层即将异常")
   fff()
   fmt.Println("外层异常后")
   defer func() {
      fmt.Println("外层异常后defer")
   }()
}

func fff() {
   fmt.Println("内层开始")
   defer func() {
      fmt.Println("内层recover前的defer")
   }()

   defer func() {
      fmt.Println("内层准备recover")
      if err := recover(); err != nil {
         // err 是 panic传入的内容
         fmt.Printf("%#v-%#v\n", "内层", err)
      }
      fmt.Println("内层完成recover")
   }()

   panic("异常信息")

   defer func() {
      fmt.Println("内层异常后的defer")
   }()

   //recover捕获的一级或者完全不捕获,这里开始下面的代码不会再执行
   fmt.Println("内层异常后语句")
}

Go语言的并发

package main

import (
   "fmt"
   "time"
)

func say(s string) {
   for i := 0; i < 5; i++ {
      time.Sleep(100 * time.Millisecond)
      fmt.Println(s)
   }
}

func main() {
   /*
      Go语言支持并发,我们只需要通过go关键字来开启goroutine就行
      goroutine是轻量级线程,goroutine的调度是由Golang运行时进行管理的
   */
   go say("world")
   say("hello")
   //输出的hello和world没有固定的先后顺序,因为它们在两个goroutine上执行

}

/*
   通道(channel)是用来传递数据的一个数据结构
   通道可用于两个goroutine之间通过传递一个指定类型的值来同步运行和通讯
   操作符<-用于指定通道的方向,发送或接收
   若没有指定方向,则为双向通道
*/

package main

import "fmt"

func sum(s []int, c chan int) {
   sum := 0
   for _, v := range s {
      sum += v
   }
   c <- sum //把sum发送到通道c
}

func main() {
   s := []int{7, 2, 8, -7, 1, 0}
   c := make(chan int)

   go sum(s[:len(s)/2], c) //从 0 到 len/2 的元素值相加
   go sum(s[len(s)/2:], c) //从 len/2 到 最后的元素值相加

   x, y := <-c, <-c //从通道c中接收

   fmt.Println(x, y, x+y)

   go sum(s[:len(s)/2], c) //给上述注释给出证明
   z := <-c
   fmt.Println(z)
}

/*
通道缓冲区
*/
package main

import "fmt"

func main() {
   //定义一个可以存储整数类型的带缓冲通道
   ch := make(chan int, 2) //缓冲区大小为2

   //带缓冲通道可以同时发送两个数据,而不用立刻去同步读取数据
   ch <- 'a'
   ch <- 2

   //获取这两个数据
   fmt.Println(<-ch)
   fmt.Println(<-ch)
}

package main

import "fmt"

func fibonacci(n int, c chan int) {
   x, y := 0, 1
   for i := 0; i < n; i++ {
      c <- x
      x, y = y, x+y
   }
   close(c)
}

/*
range 函数遍历每个从通道接收到的数据,通道c在发送完10个数据后就把通道关闭了
所以我们在接收第11个数据的时候就阻塞了
*/
func main() {
   c := make(chan int, 10)
   go fibonacci(cap(c), c)

   for i := range c {
      fmt.Println(i)
   }
}

Go语言的使用工具

我使用的工具是Goland,一个IDE,非常好用,就是有点贵,可以去淘宝上买激活码,或者去百度上搜方法,建议直接淘宝解决,反正就一丢丢钱,时间可是很宝贵的,别浪费太多时间在工具上。也有其他好用的工具,但我更喜欢这个IDE,更方便。