go 接口,go接口和继承对比,go 继承,go多态,go类型断言,Go 处理大数组:使用 for range 还是 for 循环?

接口

https://draveness.me/golang/docs/part2-foundation/ch04-basic/golang-interface/#421-概述

  • 在 Java 中:实现接口需要显式地声明接口并实现所有方法;
  • 在 Go 中:实现接口的所有方法就隐式地实现了接口

接口实例1

package main

import (
  "fmt"
  "testing"
)

type USB interface {
  // 声明了两个没有实现的方法
  Start()
  Stop()
}
type Phone struct {
}

// 让Phone实现USB接口方法
func (p Phone) Start() {
  fmt.Println("手机开始工作")
}
func (p Phone) Stop() {
  fmt.Println("手机停止工作")
}

type Camera struct {
}

func (c Camera) Start() {
  fmt.Println("相机开始工作")
}

//如果只实现Start()不实现Stop()编译器会报错 cannot use ca (variable of type Camera) as USB value in argument to c.Working: missing method Stop
func (c Camera) Stop() {
  fmt.Println("相机停止工作")
}

type Computer struct {
}

// 编写一个方法Working方法,接受一个USB接口类型变量
// 只要实现USB接口(所为实现USB接口,指的是实现了USB接口生命的所有方法)
func (c Computer) Working(u USB) { //USB变量会根据传入的参数,来判断到底是Phone还是Camera
  // 通过USB接口变量来调用Start和Stop方法
  u.Start()
  u.Stop()
}
func TestMain(t *testing.T) {
  c := Computer{}
  p := Phone{}
  ca := Camera{}
  c.Working(p)
  c.Working(ca)
  fmt.Println("执行完成!")
}

接口实例2

package main

import (
  "fmt"
  "testing"
)

type USB interface {
  Say()
}
type Stu struct {
}

// *Stu结构体指针类型来实现
func (s *Stu) Say() {
  fmt.Println("func (s *Stu) Say() {")
}

func TestMain(t *testing.T) {
  var stu Stu = Stu{}
  // Stu类型没有实现USB接口
  //编译阶段报错:cannot use stu (variable of type Stu) as USB value in variable declaration: missing method Say (Say has pointer receiver)
  // var usb USB = stu
  var usb USB = &stu //正确写法
  usb.Say()
  fmt.Println("ok")
}

接口和继承对比

  • 接口和继承解决的解决的问题不同
    继承的价值主要在于:解决代码的复用性和可维护性。
    接口的价值主要在于:设计,设计好各种规范(方法),让其它自定义类型去实现这些方法。
  • 接口比继承更加灵活Person StudentBirdAble LittleMonkey
    接口比继承更加灵活,继承是满足is- a的关系,而接口只需满足like - a的关系。
  • 接口在一定程度上实现代码解耦

接口注意事项

  • 接口中不能有相同的方法名,编译报错:重复定义;

继承

package main

import (
  "fmt"
  "testing"
)

type Monkey struct {
  Name string `json:"name"`
}
type BirdAble interface {
  Flying()
}
type FishAble interface {
  Swimming()
}

func (m *Monkey) climbing() {
  fmt.Println(m.Name, "生下来会爬树")
}

type LittleMonkey struct {
  Monkey //继承
}

func (l *LittleMonkey) Flying() {
  fmt.Println(l.Name, "会飞天~~~")
}
func (l *LittleMonkey) Swimming() {
  fmt.Println(l.Name, "会游泳))))")
}

func TestMain(t *testing.T) {
  monkey := LittleMonkey{
    Monkey{Name: "king"},
  }
  monkey.climbing()
  monkey.Flying()
  monkey.Swimming()
  fmt.Println("执行完成!")
}

多态

同接口实例1

类型断言

类型断言,由于接口是一般类型,不知道具体类型,如果要转成具体类型,就需要使用类型断言

接口interface转结构体(类型断言)

data := client.ReceivePTZData()
rdata := data.(dsd.Position)
point.Positions = rdata

类型断言(带检测)

func TestAssert(t *testing.T) {
  
  var x interface{}
  var y float32 = 2.2
  x = y //空接口可以接受任意类型

  // 类型断言(带检测的)
  if y,ok:=x.(float32);ok{
    fmt.Println("assert ok")
    fmt.Printf("y 的类型是 %T 值是:%v", y,y)
  }else{
    fmt.Println("assert fail")
  }
  fmt.Println("执行结束")
}

Go 处理大数组:使用 for range 还是 for 循环?

https://mp.weixin.qq.com/s/TsRJWpbrMbN6jVISAvY-HQ

  • 数组和切片for和for range遍历性能相差无几,切片底层是数组指针。
  • 随着结构体字段的增加for和for range遍历性能降低。

数组

for range 循环是 range 表达式的副本。

package main

import "testing"

func BenchmarkClassicForLoopIntArray(b *testing.B) {
  b.ReportAllocs()
  var arr [100000]int
  for i := 0; i < b.N; i++ {
    for j := 0; j < len(arr); j++ {
      arr[j] = j
    }
  }
}

func BenchmarkForRangeIntArray(b *testing.B) {
  b.ReportAllocs()
  var arr [100000]int
  for i := 0; i < b.N; i++ {
    for j, v := range arr {
      arr[j] = j
      _ = v
    }
  }
}

/*
ling@ling:~/go/src/neuron/function/visca/afor$ go test -bench . a_test.go 
goos: linux
goarch: amd64
cpu: Intel(R) Core(TM) i7-10700 CPU @ 2.90GHz
BenchmarkClassicForLoopIntArray-4          26080             45537 ns/op               0 B/op          0 allocs/op
BenchmarkForRangeIntArray-4                40189             28805 ns/op               0 B/op          0 allocs/op
PASS
ok      command-line-arguments  3.124s
*/

由于在 Go 中切片的底层都是通过数组来存储数据,尽管有 for range 的副本复制问题,但是切片副本指向的底层数组与原切片是一致的。这意味着,当我们将数组通过切片代替后,不管是通过 for range 或者 for 循环均能得到一致的稳定的遍历性能。

结构体

package main

import "testing"

type U5 struct {
  a, b, c, d, e int
}
type U4 struct {
  a, b, c, d int
}
type U3 struct {
  b, c, d int
}
type U2 struct {
  c, d int
}
type U1 struct {
  d int
}

func BenchmarkClassicForLoopLargeStructArrayU5(b *testing.B) {
  b.ReportAllocs()
  var arr [100000]U5
  for i := 0; i < b.N; i++ {
    for j := 0; j < len(arr)-1; j++ {
      arr[j].d = j
    }
  }
}
func BenchmarkClassicForLoopLargeStructArrayU4(b *testing.B) {
  b.ReportAllocs()
  var arr [100000]U4
  for i := 0; i < b.N; i++ {
    for j := 0; j < len(arr)-1; j++ {
      arr[j].d = j
    }
  }
}
func BenchmarkClassicForLoopLargeStructArrayU3(b *testing.B) {
  b.ReportAllocs()
  var arr [100000]U3
  for i := 0; i < b.N; i++ {
    for j := 0; j < len(arr)-1; j++ {
      arr[j].d = j
    }
  }
}
func BenchmarkClassicForLoopLargeStructArrayU2(b *testing.B) {
  b.ReportAllocs()
  var arr [100000]U2
  for i := 0; i < b.N; i++ {
    for j := 0; j < len(arr)-1; j++ {
      arr[j].d = j
    }
  }
}

func BenchmarkClassicForLoopLargeStructArrayU1(b *testing.B) {
  b.ReportAllocs()
  var arr [100000]U1
  for i := 0; i < b.N; i++ {
    for j := 0; j < len(arr)-1; j++ {
      arr[j].d = j
    }
  }
}

func BenchmarkForRangeLargeStructArrayU5(b *testing.B) {
  b.ReportAllocs()
  var arr [100000]U5
  for i := 0; i < b.N; i++ {
    for j, v := range arr {
      arr[j].d = j
      _ = v
    }
  }
}
func BenchmarkForRangeLargeStructArrayU4(b *testing.B) {
  b.ReportAllocs()
  var arr [100000]U4
  for i := 0; i < b.N; i++ {
    for j, v := range arr {
      arr[j].d = j
      _ = v
    }
  }
}

func BenchmarkForRangeLargeStructArrayU3(b *testing.B) {
  b.ReportAllocs()
  var arr [100000]U3
  for i := 0; i < b.N; i++ {
    for j, v := range arr {
      arr[j].d = j
      _ = v
    }
  }
}
func BenchmarkForRangeLargeStructArrayU2(b *testing.B) {
  b.ReportAllocs()
  var arr [100000]U2
  for i := 0; i < b.N; i++ {
    for j, v := range arr {
      arr[j].d = j
      _ = v
    }
  }
}
func BenchmarkForRangeLargeStructArrayU1(b *testing.B) {
  b.ReportAllocs()
  var arr [100000]U1
  for i := 0; i < b.N; i++ {
    for j, v := range arr {
      arr[j].d = j
      _ = v
    }
  }
}

/*
ling@ling:~/go/src/neuron/function/visca/aforr$ go test -bench . a_test.go 
goos: linux
goarch: amd64
cpu: Intel(R) Core(TM) i7-10700 CPU @ 2.90GHz
BenchmarkClassicForLoopLargeStructArrayU5-4        24024             47806 ns/op               0 B/op          0 allocs/op
BenchmarkClassicForLoopLargeStructArrayU4-4        24262             52619 ns/op               0 B/op          0 allocs/op
BenchmarkClassicForLoopLargeStructArrayU3-4        21996             47978 ns/op               0 B/op          0 allocs/op
BenchmarkClassicForLoopLargeStructArrayU2-4        25250             47261 ns/op               0 B/op          0 allocs/op
BenchmarkClassicForLoopLargeStructArrayU1-4        25111             48429 ns/op               0 B/op          0 allocs/op
BenchmarkForRangeLargeStructArrayU5-4               4347            269507 ns/op               0 B/op          0 allocs/op
BenchmarkForRangeLargeStructArrayU4-4               4981            213281 ns/op               0 B/op          0 allocs/op
BenchmarkForRangeLargeStructArrayU3-4               7382            149709 ns/op               0 B/op          0 allocs/op
BenchmarkForRangeLargeStructArrayU2-4              11006            108065 ns/op               0 B/op          0 allocs/op
BenchmarkForRangeLargeStructArrayU1-4              38036             30441 ns/op               0 B/op          0 allocs/op
PASS
ok      command-line-arguments  16.051s
*/

我们看到一个现象:不管是什么类型的结构体元素数组,经典的 for 循环遍历的性能比较一致,但是 for range 的遍历性能会随着结构字段数量的增加而降低。

posted @ 2022-05-27 16:45  凌易说-lingyisay  阅读(55)  评论(0编辑  收藏  举报