为什么要使用接口</h1>
<pre><code class="lang-go hljs"><span class="token keyword">type</span> Cat <span class="token keyword">struct</span><span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token keyword">func</span> <span class="token punctuation">(</span>c Cat<span class="token punctuation">)</span> <span class="token function">Say</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token builtin">string</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token operator">&</span>quot<span class="token punctuation">;</span>喵喵喵<span class="token operator">&</span>quot<span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token keyword">type</span> Dog <span class="token keyword">struct</span><span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token keyword">func</span> <span class="token punctuation">(</span>d Dog<span class="token punctuation">)</span> <span class="token function">Say</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token builtin">string</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token operator">&</span>quot<span class="token punctuation">;</span>汪汪汪<span class="token operator">&</span>quot<span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
c <span class="token operator">:=</span> Cat<span class="token punctuation">{</span><span class="token punctuation">}</span>
fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token operator">&</span>quot<span class="token punctuation">;</span>猫<span class="token punctuation">:</span><span class="token operator">&</span>quot<span class="token punctuation">;</span><span class="token punctuation">,</span> c<span class="token punctuation">.</span><span class="token function">Say</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
d <span class="token operator">:=</span> Dog<span class="token punctuation">{</span><span class="token punctuation">}</span>
fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token operator">&</span>quot<span class="token punctuation">;</span>狗<span class="token punctuation">:</span><span class="token operator">&</span>quot<span class="token punctuation">;</span><span class="token punctuation">,</span> d<span class="token punctuation">.</span><span class="token function">Say</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre>
上面的代码中定义了猫和狗,然后它们都会叫,你会发现main函数中明显有重复的代码,如果我们后续再加上猪、青蛙等动物的话,我们的代码还会一直重复下去。那我们能不能把它们当成“能叫的动物”来处理呢?
像类似的例子在我们编程过程中会经常遇到:
比如一个网上商城可能使用支付宝、微信、银联等方式去在线支付,我们能不能把它们当成“支付方式”来处理呢?
比如三角形,四边形,圆形都能计算周长和面积,我们能不能把它们当成“图形”来处理呢?
比如销售、行政、程序员都能计算月薪,我们能不能把他们当成“员工”来处理呢?
Go语言中为了解决类似上面的问题,就设计了接口这个概念。接口区别于我们之前所有的具体类型,接口是一种抽象的类型。当你看到一个接口类型的值时,你不知道它是什么,唯一知道的是通过它的方法能做什么。
<h1>实现接口的条件</h1>
一个对象只要全部实现了接口中的方法,那么就实现了这个接口。换句话说,接口就是一个需要实现的方法列表。
我们来定义一个<code>Sayer</code>接口:
<pre><code class="lang-go hljs"><span class="token comment">// Sayer 接口</span>
<span class="token keyword">type</span> Sayer <span class="token keyword">interface</span> <span class="token punctuation">{</span>
<span class="token function">say</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre>
定义<code>dog</code>和<code>cat</code>两个结构体:
<pre><code class="lang-go hljs"><span class="token keyword">type</span> dog <span class="token keyword">struct</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token keyword">type</span> cat <span class="token keyword">struct</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
</code></pre>
因为<code>Sayer</code>接口里只有一个<code>say</code>方法,所以我们只需要给<code>dog</code>和<code>cat</code>分别实现<code>say</code>方法就可以实现<code>Sayer</code>接口了。
<pre><code class="lang-go hljs"><span class="token comment">// dog实现了Sayer接口</span>
<span class="token keyword">func</span> <span class="token punctuation">(</span>d dog<span class="token punctuation">)</span> <span class="token function">say</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token operator">&</span>quot<span class="token punctuation">;</span>汪汪汪<span class="token operator">&</span>quot<span class="token punctuation">;</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token comment">// cat实现了Sayer接口</span>
<span class="token keyword">func</span> <span class="token punctuation">(</span>c cat<span class="token punctuation">)</span> <span class="token function">say</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token operator">&</span>quot<span class="token punctuation">;</span>喵喵喵<span class="token operator">&</span>quot<span class="token punctuation">;</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre>
接口的实现就是这么简单,只要实现了接口中的所有方法,就实现了这个接口。
<h1>多个类型实现同一接口</h1>
Go语言中不同的类型还可以实现同一接口 首先我们定义一个<code>Mover</code>接口,它要求必须由一个<code>move</code>方法。
<pre><code class="lang-go hljs"><span class="token comment">// Mover 接口</span>
<span class="token keyword">type</span> Mover <span class="token keyword">interface</span> <span class="token punctuation">{</span>
<span class="token function">move</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre>
例如狗可以动,汽车也可以动,可以使用如下代码实现这个关系:
<pre><code class="lang-go hljs"><span class="token keyword">type</span> dog <span class="token keyword">struct</span> <span class="token punctuation">{</span>
name <span class="token builtin">string</span>
<span class="token punctuation">}</span>
<span class="token keyword">type</span> car <span class="token keyword">struct</span> <span class="token punctuation">{</span>
brand <span class="token builtin">string</span>
<span class="token punctuation">}</span>
<span class="token comment">// dog类型实现Mover接口</span>
<span class="token keyword">func</span> <span class="token punctuation">(</span>d dog<span class="token punctuation">)</span> <span class="token function">move</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
fmt<span class="token punctuation">.</span><span class="token function">Printf</span><span class="token punctuation">(</span><span class="token operator">&</span>quot<span class="token punctuation">;</span><span class="token operator">%</span>s会跑\n<span class="token operator">&</span>quot<span class="token punctuation">;</span><span class="token punctuation">,</span> d<span class="token punctuation">.</span>name<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token comment">// car类型实现Mover接口</span>
<span class="token keyword">func</span> <span class="token punctuation">(</span>c car<span class="token punctuation">)</span> <span class="token function">move</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
fmt<span class="token punctuation">.</span><span class="token function">Printf</span><span class="token punctuation">(</span><span class="token operator">&</span>quot<span class="token punctuation">;</span><span class="token operator">%</span>s速度<span class="token number">70</span>迈\n<span class="token operator">&</span>quot<span class="token punctuation">;</span><span class="token punctuation">,</span> c<span class="token punctuation">.</span>brand<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre>
这个时候我们在代码中就可以把狗和汽车当成一个会动的物体来处理了,不再需要关注它们具体是什么,只需要调用它们的<code>move</code>方法就可以了。
<pre><code class="lang-go hljs"><span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">var</span> x Mover
<span class="token keyword">var</span> a <span class="token operator">=</span> dog<span class="token punctuation">{</span>name<span class="token punctuation">:</span> <span class="token operator">&</span>quot<span class="token punctuation">;</span>旺财<span class="token operator">&</span>quot<span class="token punctuation">;</span><span class="token punctuation">}</span>
<span class="token keyword">var</span> b <span class="token operator">=</span> car<span class="token punctuation">{</span>brand<span class="token punctuation">:</span> <span class="token operator">&</span>quot<span class="token punctuation">;</span>保时捷<span class="token operator">&</span>quot<span class="token punctuation">;</span><span class="token punctuation">}</span>
x <span class="token operator">=</span> a
x<span class="token punctuation">.</span><span class="token function">move</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
x <span class="token operator">=</span> b
x<span class="token punctuation">.</span><span class="token function">move</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre>
上面的代码执行结果如下:
<pre><code class="lang-go hljs">旺财会跑
保时捷速度<span class="token number">70</span>迈
</code></pre>
并且一个接口的方法,不一定需要由一个类型完全实现,接口的方法可以通过在类型中嵌入其他类型或者结构体来实现。
<pre><code class="lang-go hljs"><span class="token comment">// WashingMachine 洗衣机</span>
<span class="token keyword">type</span> WashingMachine <span class="token keyword">interface</span> <span class="token punctuation">{</span>
<span class="token function">wash</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token function">dry</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token comment">// 甩干器</span>
<span class="token keyword">type</span> dryer <span class="token keyword">struct</span><span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token comment">// 实现WashingMachine接口的dry()方法</span>
<span class="token keyword">func</span> <span class="token punctuation">(</span>d dryer<span class="token punctuation">)</span> <span class="token function">dry</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token operator">&</span>quot<span class="token punctuation">;</span>甩一甩<span class="token operator">&</span>quot<span class="token punctuation">;</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token comment">// 海尔洗衣机</span>
<span class="token keyword">type</span> haier <span class="token keyword">struct</span> <span class="token punctuation">{</span>
dryer <span class="token comment">//嵌入甩干器</span>
<span class="token punctuation">}</span>
<span class="token comment">// 实现WashingMachine接口的wash()方法</span>
<span class="token keyword">func</span> <span class="token punctuation">(</span>h haier<span class="token punctuation">)</span> <span class="token function">wash</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token operator">&</span>quot<span class="token punctuation">;</span>洗刷刷<span class="token operator">&</span>quot<span class="token punctuation">;</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre>
<h1>接口值</h1>
一个接口的值(简称接口值)是由<code>一个具体类型</code>和<code>具体类型的值</code>两部分组成的。这两部分分别称为接口的<code>动态类型</code>和<code>动态值</code>。
我们来看一个具体的例子:
<pre><code class="lang-go hljs"><span class="token keyword">var</span> w io<span class="token punctuation">.</span>Writer
w <span class="token operator">=</span> os<span class="token punctuation">.</span>Stdout
w <span class="token operator">=</span> <span class="token function">new</span><span class="token punctuation">(</span>bytes<span class="token punctuation">.</span>Buffer<span class="token punctuation">)</span>
w <span class="token operator">=</span> <span class="token boolean">nil</span>
</code></pre>
请看下图分解:
想要判断空接口中的值这个时候就可以使用类型断言,其语法格式:
<pre><code class="lang-go hljs">x<span class="token punctuation">.</span><span class="token punctuation">(</span>T<span class="token punctuation">)</span>
</code></pre>
其中:
<ul><li>x:表示类型为<code>interface{}</code>的变量</li><li>T:表示断言<code>x</code>可能是的类型。</li></ul>该语法返回两个参数,第一个参数是<code>x</code>转化为<code>T</code>类型后的变量,第二个值是一个布尔值,若为<code>true</code>则表示断言成功,为<code>false</code>则表示断言失败。
举个例子:
<pre><code class="lang-go hljs"><span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">var</span> x <span class="token keyword">interface</span><span class="token punctuation">{</span><span class="token punctuation">}</span>
x <span class="token operator">=</span> <span class="token operator">&</span>quot<span class="token punctuation">;</span>Hello 沙河<span class="token operator">&</span>quot<span class="token punctuation">;</span>
v<span class="token punctuation">,</span> ok <span class="token operator">:=</span> x<span class="token punctuation">.</span><span class="token punctuation">(</span><span class="token builtin">string</span><span class="token punctuation">)</span>
<span class="token keyword">if</span> ok <span class="token punctuation">{</span>
fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span>v<span class="token punctuation">)</span>
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token operator">&</span>quot<span class="token punctuation">;</span>类型断言失败<span class="token operator">&</span>quot<span class="token punctuation">;</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
上面的示例中如果要断言多次就需要写多个<code>if</code>判断,这个时候我们可以使用<code>switch</code>语句来实现:
<pre><code class="lang-go hljs"><span class="token keyword">func</span> <span class="token function">justifyType</span><span class="token punctuation">(</span>x <span class="token keyword">interface</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">switch</span> v <span class="token operator">:=</span> x<span class="token punctuation">.</span><span class="token punctuation">(</span><span class="token keyword">type</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">case</span> <span class="token builtin">string</span><span class="token punctuation">:</span>
fmt<span class="token punctuation">.</span><span class="token function">Printf</span><span class="token punctuation">(</span><span class="token operator">&</span>quot<span class="token punctuation">;</span>x is a <span class="token builtin">string</span>,value is <span class="token operator">%</span>v\n<span class="token operator">&</span>quot<span class="token punctuation">;</span><span class="token punctuation">,</span> v<span class="token punctuation">)</span>
<span class="token keyword">case</span> <span class="token builtin">int</span><span class="token punctuation">:</span>
fmt<span class="token punctuation">.</span><span class="token function">Printf</span><span class="token punctuation">(</span><span class="token operator">&</span>quot<span class="token punctuation">;</span>x is a <span class="token builtin">int</span> is <span class="token operator">%</span>v\n<span class="token operator">&</span>quot<span class="token punctuation">;</span><span class="token punctuation">,</span> v<span class="token punctuation">)</span>
<span class="token keyword">case</span> <span class="token builtin">bool</span><span class="token punctuation">:</span>
fmt<span class="token punctuation">.</span><span class="token function">Printf</span><span class="token punctuation">(</span><span class="token operator">&</span>quot<span class="token punctuation">;</span>x is a <span class="token builtin">bool</span> is <span class="token operator">%</span>v\n<span class="token operator">&</span>quot<span class="token punctuation">;</span><span class="token punctuation">,</span> v<span class="token punctuation">)</span>
<span class="token keyword">default</span><span class="token punctuation">:</span>
fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token operator">&</span>quot<span class="token punctuation">;</span>unsupport <span class="token keyword">type</span>!<span class="token operator">&</span>quot<span class="token punctuation">;</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
因为空接口可以存储任意类型值的特点,所以空接口在Go语言中的使用十分广泛。
关于接口需要注意的是,只有当有两个或两个以上的具体类型必须以相同的方式进行处理时才需要定义接口。不要为了接口而写接口,那样只会增加不必要的抽象,导致不必要的运行时损耗。
<blockquote class="layui-elem-quote" style="width: 100%;overflow:hidden">
作者: lipenghandsome
链接: https://blog.csdn.net/lipenghandsome/article/details/105916687
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
</blockquote>
到此这篇关于“Go语言基础之接口”的文章就介绍到这了,更多文章或继续浏览下面的相关文章,希望大家以后多多支持JQ教程网!
您可能感兴趣的文章:
想系统学习GO语言(Golang
GO语言零基础从入门到精通视频教程
go 获取函数地址_Go语言基础--接口浅析
Go语言发展历史、核心、特性及学习路线
Go语言的函数、方法和接口
Go 语言到底适合干什么?
2018年最全Go语言教程零基础入门到进阶实战视频
基于类型系统的面向对象编程语言Go
Go 语言十年而立,Go2 蓄势待发
从零开始学习GO语言-搭建Go语言开发环境-快速开发入门第一个小程序