欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 人文社科 > 生活经验 >内容正文

生活经验

Go 分布式学习利器(13)-- Go语言的多态

发布时间:2023/11/27 生活经验 35 豆豆
生活随笔 收集整理的这篇文章主要介绍了 Go 分布式学习利器(13)-- Go语言的多态 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

文章目录

    • 1. 基本的多态实现
    • 2. 空接口与断言
    • 3. Go接口的最佳实践

1. 基本的多态实现

我们知道C++中实现多态是通过虚函数表 和 继承来 实现的。
类似如下代码:

复制代码class Programmar{
public:virtual void write_hello_world() = 0;
}class GoProgrammar: public Programmar{
public:void write_hello_world() {printf("Go write hello workld\n");}
}class CXXProgrammar: public Programmar{
public:void write_hello_world() {printf("C++ write hello workld\n");}
}class JavaProgrammar: public Programmar{
public:void write_hello_world() {printf("Java write hello workld\n");}
}void write_program(Programmar p) {p.write_hello_world();
}

通过将不同类型的Programmar子类对象传入到write_program函数中即能够调用对应子类的实现,达到使用父类的成员调用子类方法的目的,且调用过程是动态绑定的,即在真正开始运行的时候父类对象才能够知道自己真正的类型是什么。

Go语言不支持继承,那么Go语言是否也能够实现如上C++/Java类似的多态呢?
模拟以上代码,画出如下类图,希望Go语言能够实现该类图中的多态功能。

如下代码:

复制代码package orientedimport ("fmt""testing"
)type Code string
type Programmar interface {WriteHelloWorld() Code
}type GoProgrammar struct {
}func (p *GoProgrammar) WriteHelloWorld() Code{return "fmt.Println(\"Go write hello world\")";
}type JavaProgrammar struct {
}func (p *JavaProgrammar) WriteHelloWorld() Code{return "fmt.Println(\"Java write hello world\")";
}func writeFirstProgram(p Programmar) {fmt.Printf("%T %v\n",p,p.WriteHelloWorld())
}func TestMulti(t *testing.T){// new 关键字创建的实例是指针类型,同时GoProgrammar是interface 结构,也是只能对应指针类型的实例goPro := new(GoProgrammar)javaPro := new(JavaProgrammar)writeFirstProgram(goPro)writeFirstProgram(javaPro)
}

最后输出如下:

复制代码=== RUN   TestMulti
*oriented.GoProgrammar fmt.Println("Go write hello world")
*oriented.JavaProgrammar fmt.Println("Java write hello world")
--- PASS: TestMulti (0.00s)

这样的多态实现,显然是OK的。

2. 空接口与断言

  1. 空接口可以表示 任何类型。 p interface{} 表示声明了一个空接口变量 p
  2. 通过断言 可以将空接口转为指定类型
    类似:v,ok := p.(int),其中ok表示是否转换成功,成功的话v中才有值

如下测试代码:

复制代码package empty_interfaceimport ("fmt""testing"
)func Dosomething(p interface{}){if v,ok := p.(int); ok{fmt.Println("Integer :", v)return}if v,ok := p.(string); ok{fmt.Println("String :", v)return}fmt.Print("Unkown\n")
}// 重构以上代码,使用switch 关键字看起来会更加简洁
func DosomthingSwitch(p interface{}) {switch v := p.(type) {case int:fmt.Println("Integer :", v)case string:fmt.Println("String :", v)default:fmt.Print("Unkown\n")}
}func TestInterface(t *testing.T) {Dosomething(10);Dosomething("test");DosomthingSwitch(111)
}

最后的输出如下:

复制代码=== RUN   TestInterface
Integer : 10
String : test
Integer : 111
--- PASS: TestInterface (0.00s)

3. Go接口的最佳实践

为了让Go代码看起来更整洁,有以下几个关于接口的编程规范/建议:

  • 在Go语言中 倾向使用较小的接口定义,很多接口只包含一个方法。
    复制代码type Reader interface{Read(p []byte) (n int, err error)
    }
    type Writer interface{Write(p []byte) (n int, err error)
    }
    
  • 较大的接口则可以由更多较小的接口组成
    复制代码type FileOp interface {ReaderWriter
    }
    
  • 只依赖与必要功能的最小接口
    复制代码func getData(read Reader) error {...
    }
    
    其中getData函数用到了Reader接口,则只需要传入Reader参数即可,不需要将FileOp都传入进来,从而降低接口的可复用性。意思是说,如果传入了FileOp,因为它包含了两个接口类型,那么两个接口类型的函数都需要被实现,但其实只用到Reader的函数,这就很不友好。

总结

以上是生活随笔为你收集整理的Go 分布式学习利器(13)-- Go语言的多态的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。