golang-learning-eight.png
8.png
大家好,我是谢伟,是一名程序员。
下面的学习是一个系列,力求从初学者的角度学会go 语言,达到中级程序员水平。
这一系列是我的输出总结,同时我还推出了视频版。正在制作过程。
为写出这些文章,我阅读了网上诸多热门的教程和纸质书籍。内容的实质都是那些,要区分出差异的话,只能表现在具体实例层面。所以,实例我会选取自己在工作中的项目实例抽取出来。希望对大家有所帮助。
我们已经研究了:
本节的主题是:接口
接口是 golang 中最值得强调的特性。它让面向对象,内容组织实现非常的方便。
接口在 go 语言中是一系列方法的集合,原则上方法可以有很多个,但建议4个左右。
type HttpClient interface {
Get(string) ([]byte, error)
Post(string, map[string]interface{}) ([]byte, error)
Put(string, map[string]interface{}) ([]byte, error)
Delete(string) (int, error)
}
上文中定义了一个 httpClient 的接口,指定了这个接口可以干这些活:Get、Post、Put、Delete
上文中指定了 httpClient 接口,指定了这个接口需要干的活是:Get、Post、Put、Delete
, 具体的实现需要靠其他结构体来实现。
type HttpImpl struct {
}
func (this *HttpImpl) Get(url string) ([]byte, error) {
var (
resq *http.Response
err error
)
if resq, err = http.Get(url); err != nil {
return nil, ErrorHttpNil
}
defer resq.Body.Close()
var (
resp []byte
)
if resp, err = ioutil.ReadAll(resq.Body); err != nil {
return nil, ErrorByteNil
}
return resp, nil
}
func (this *HttpImpl) Post(url string, body map[string]interface{}) ([]byte, error) {
return nil, nil
}
func (this *HttpImpl) Put(url string, body map[string]interface{}) ([]byte, error) {
return nil, nil
}
func (this *HttpImpl) Delete(url string) (int, error) {
return 0, nil
}
httpImpl
, 这个结构体存在Get、Post、Put、Delete
四个方法,参数和返回值的类型和步骤一定义的接口的方法的参数和返回值一致。httpImpl
还可以有其他的方法,但不重要,重要的是存在接口中定义的那四个方法httpImpl
实现了接口 HttpClient
一个结构体实现了接口要求的所有的方法(方法的参数和返回值一致),那么就说这个结构体实现了这个接口
接口可以屏蔽内部细节,和具体的实现方法。只关注我需要做什么,而不关注怎么做。
func main() {
var httpImpl = &HttpImpl{} // 结构体
var httpClient HttpClient // 接口
httpClient = httpImpl // 接口赋值
responseOne, _ := httpClient.Get("https://www.jianshu.com/u/58f0817209aa")
fmt.Println(string([]byte(responseOne)))
}
上文中的使用:httpClient
屏蔽了 httpImpl
的内部细节,而依然可以使用 Get
方法,去完成任务。
当然接口可以被诸多结构体实现,只需存在接口定义的几种方法即可。
接口和结构体的定义很相似,也可以完成嵌入接口的功能,嵌入的匿名的接口,可以自动的具备被嵌入的接口的方法。
type InterHttpClient interface {
HttpClient
}
func main() {
var httpImpl = &HttpImpl{}
var httpClient HttpClient
httpClient = httpImpl
responseOne, _ := httpClient.Get("https://www.jianshu.com/u/58f0817209aa")
fmt.Println(string([]byte(responseOne)))
// interHttpClient
var interHttpClient InterHttpClient
interHttpClient = httpImpl
responseTwo, _ := interHttpClient.Get("http://www.gitbub.com")
fmt.Println(string([]byte(responseTwo)))
}
InterHttpClient
嵌入接口 HttpClient
, 而自动具备方法:Get、Post、Put、Delete
HttpImpl
结构体也实现了接口InterHttpClient
type Stringer interface {
String() string
}
结构体实现 String
方法即可实现结构化输出结构体。
type error interface {
Error() string
}
实现Error 方法即可自定义错误类型。
type Reader interface {
Read(p []byte) (n int, err error)
}
type Writer interface {
Write(p []byte) (n int, err error)
}
type ReadWriter interface {
Reader
Writer
}
这几个读写接口在好些库中实现了,后续我们再讨论。
Any 类型
interface{}
空接口在 go 里,可以当成任意类型,意味着,比如你的函数或者方法不知道传入的参数的类型,可以直接定义为 interface{}
func Say(name interface{}) {
fmt.Println(name)
}
类型断言
类型断言的使用场景是:接口类型的变量可以包含任何类型的值。如何判断变量的真实类型?
比如解析一个不知道字段类型的 json, 常常需要使用到类型断言。
可以使用:
ok...idiom
varInterface.(T), varInterface 必须是接口、T 则是具体的实现接口的结构体
func main() {
var httpImpl = &HttpImpl{}
var httpClient HttpClient
httpClient = httpImpl
responseOne, _ := httpClient.Get("https://www.jianshu.com/u/58f0817209aa")
fmt.Println(string([]byte(responseOne)))
// interHttpClient
var interHttpClient InterHttpClient
interHttpClient = httpImpl
responseTwo, _ := interHttpClient.Get("http://www.gitbub.com")
fmt.Println(string([]byte(responseTwo)))
// ok..idiom
if n, ok := httpClient.(*HttpImpl); ok {
fmt.Println(n)
}
if m, ok := interHttpClient.(*HttpImpl); ok {
fmt.Println(m)
}
}
switch ..case...
.(type) 只在 switch 语句里才能使用。
func Show(param interface{}) {
switch param.(type) {
case *HttpImpl:
fmt.Println("1")
default:
fmt.Println("0")
}
}
func main() {
var httpImpl = &HttpImpl{}
var httpClient HttpClient
httpClient = httpImpl
responseOne, _ := httpClient.Get("https://www.jianshu.com/u/58f0817209aa")
fmt.Println(string([]byte(responseOne)))
// interHttpClient
var interHttpClient InterHttpClient
interHttpClient = httpImpl
responseTwo, _ := interHttpClient.Get("http://www.gitbub.com")
fmt.Println(string([]byte(responseTwo)))
Show(httpClient) // 1
Show(interHttpClient) // 1
以上就是接口的全部内容,接口是go 中最特别的特性。借助 接口, go 实现面向对象中的继承和多态。
接口是方法的集合,只定义具体要干什么,而怎么干,则由其他的结构体的方法实现。这样不同的结构体的方法的具体处理不同,实现的接口的功能就不一样。
尽管如此,接口并不意味着可以随意滥用。我们最好是根据面向对象的客观实体,抽象出接口和方法。
本节完,再会。