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 的遍历性能会随着结构字段数量的增加而降低。