教程集 www.jiaochengji.com
教程集 >  Golang编程  >  golang教程  >  正文 35. Go 语言中关于接口的三个规则

35. Go 语言中关于接口的三个规则

发布时间:2021-12-03   编辑:jiaochengji.com
教程集为您提供35. Go 语言中关于接口的三个规则等资源,欢迎您收藏本站,我们将为您提供最新的35. Go 语言中关于接口的三个规则资源
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;"><path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"/></svg>

Hi,大家好,我是明哥。

在自己学习 Golang 的这段时间里,我写了详细的学习笔记放在我的个人微信公众号 《Go编程时光》,对于 Go 语言,我也算是个初学者,因此写的东西应该会比较适合刚接触的同学,如果你也是刚学习 Go 语言,不防关注一下,一起学习,一起成长。

我的在线博客:http://golang.iswbm.com
我的 Github:github.com/iswbm/GolangCodingTime

<h2>1. 对方法的调用限制</h2>

接口是一组固定的方法集,由于静态类型的限制,接口变量有时仅能调用其中特定的一些方法。

请看下面这段代码

<pre><code class="lang-go hljs"><span class="token keyword">package</span> main <span class="token keyword">import</span> <span class="token string">"fmt"</span> <span class="token keyword">type</span> Phone <span class="token keyword">interface</span> <span class="token punctuation">{</span> <span class="token function">call</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">type</span> iPhone <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">func</span> <span class="token punctuation">(</span>phone iPhone<span class="token punctuation">)</span><span class="token function">call</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 string">"Hello, iPhone."</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">func</span> <span class="token punctuation">(</span>phone iPhone<span class="token punctuation">)</span><span class="token function">send_wechat</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 string">"Hello, Wechat."</span><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> <span class="token keyword">var</span> phone Phone phone <span class="token operator">=</span> iPhone<span class="token punctuation">{</span>name<span class="token punctuation">:</span><span class="token string">"ming's iphone"</span><span class="token punctuation">}</span> phone<span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token punctuation">)</span> phone<span class="token punctuation">.</span><span class="token function">send_wechat</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> </code></pre>

我定义了一个 Phone 的接口,只要求实现 call 方法即可,也就是只要能打电话的设备就是一个电话(好像是一句没用的废话)。

然后再定义了一个 iPhone 的结构体,该结构体接收两个方法,一个是打电话( call 函数),一个是发微信(send_wechat 函数)。

最后一步是关键,我们定义了一个 Phone 接口类型的 phone 对象,该对象的内容是 iPhone 结构体。然后我们调用该对象的 call 方法,一切正常。

但是当你调用 <code>phone.send_wechat</code>方法,程序会报错,提示我们 Phone 类型的方法没有 send_wechat 的字段或方法。

<pre><code class="lang-go hljs"># command<span class="token operator">-</span>line<span class="token operator">-</span>arguments <span class="token punctuation">.</span><span class="token operator">/</span>demo<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">30</span><span class="token punctuation">:</span><span class="token number">10</span><span class="token punctuation">:</span> phone<span class="token punctuation">.</span>send_wechat undefined <span class="token punctuation">(</span><span class="token keyword">type</span> Phone has no field or method send_wechat<span class="token punctuation">)</span> </code></pre>

原因也很明显,因为我们的phone对象显示声明为 Phone 接口类型,因此 phone调用的方法会受到此接口的限制。

那么如何让 phone 可以调用 send_wechat 方法呢?

答案是可以不显示的声明为 Phone接口类型 ,但要清楚 phone 对象实际上是隐式的实现了 Phone 接口,如此一来,方法的调用就不会受到接口类型的约束。

修改 main 方法成如下

<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> phone <span class="token operator">:=</span> iPhone<span class="token punctuation">{</span>name<span class="token punctuation">:</span><span class="token string">"ming's iphone"</span><span class="token punctuation">}</span> phone<span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token punctuation">)</span> phone<span class="token punctuation">.</span><span class="token function">send_wechat</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> </code></pre>

运行后,一切正常,没有报错。

<pre><code class="lang-go hljs">Hello<span class="token punctuation">,</span> iPhone<span class="token punctuation">.</span> Hello<span class="token punctuation">,</span> Wechat<span class="token punctuation">.</span> </code></pre> <h2>
2. 调用函数时的隐式转换</h2>

Go 语言中的函数调用都是值传递的,变量会在方法调用前进行类型转换。

比如下面这段代码

<pre><code class="lang-go hljs"> <span class="token keyword">import</span> <span class="token punctuation">(</span> <span class="token string">"fmt"</span> <span class="token punctuation">)</span> <span class="token keyword">func</span> <span class="token function">printType</span><span class="token punctuation">(</span>i <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> i<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">int</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 string">"参数的类型是 int"</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">Println</span><span class="token punctuation">(</span><span class="token string">"参数的类型是 string"</span><span class="token punctuation">)</span> <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> a <span class="token operator">:=</span> <span class="token number">10</span> <span class="token function">printType</span><span class="token punctuation">(</span>a<span class="token punctuation">)</span> <span class="token punctuation">}</span> </code></pre>

如果你运行后,会发现一切都很正常

<pre><code class="lang-go hljs">参数的类型是 <span class="token builtin">int</span> </code></pre>

但是如果你把函数内的内容搬到到外面来

<pre><code class="lang-go hljs"><span class="token keyword">package</span> main <span class="token keyword">import</span> <span class="token string">"fmt"</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> a <span class="token operator">:=</span> <span class="token number">10</span> <span class="token keyword">switch</span> a<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">int</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 string">"参数的类型是 int"</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">Println</span><span class="token punctuation">(</span><span class="token string">"参数的类型是 string"</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </code></pre>

就会有意想不到的结果,居然报错了。

<pre><code class="lang-go hljs"># command<span class="token operator">-</span>line<span class="token operator">-</span>arguments <span class="token punctuation">.</span><span class="token operator">/</span>demo<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">9</span><span class="token punctuation">:</span><span class="token number">5</span><span class="token punctuation">:</span> cannot <span class="token keyword">type</span> <span class="token keyword">switch</span> on non<span class="token operator">-</span><span class="token keyword">interface</span> value a <span class="token punctuation">(</span><span class="token keyword">type</span> <span class="token builtin">int</span><span class="token punctuation">)</span> </code></pre>

这个操作会让一个新人摸不着头脑,代码逻辑都是一样的,为什么一个不会报错,一个会报错呢?

原因其实很简单。

当一个函数接口 interface{} 空接口类型时,我们说它可以接收什么任意类型的参数(江湖上称之为无招胜有招)。

当你使用这种写法时,Go 会默默地为我们做一件事,就是把传入函数的参数值(注意:Go 语言中的函数调用都是值传递的)的类型隐式的转换成 interface{} 类型。

<h3>
如何进行接口类型的显示转换</h3>

上面了解了函数中 接口类型的隐式转换后,你的心里可能开始有了疑问了,难道我使用类型断言,只能通过一个接收空接口类型的函数才能实现吗?

答案当然是 No.

如果你想手动对其进行类型转换,可以像下面这样子,就可以将变量 a 的静态类型转换为 interface{} 类型然后赋值给 b (此时 a 的静态类型还是 int,而 b 的静态类型为 interface{})

<pre><code class="lang-go hljs"><span class="token keyword">var</span> a <span class="token builtin">int</span> <span class="token operator">=</span> <span class="token number">25</span> b <span class="token operator">:=</span> <span class="token keyword">interface</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">(</span>a<span class="token punctuation">)</span> </code></pre>

知道了方法后,将代码修改成如下:

<pre><code class="lang-go hljs"><span class="token keyword">package</span> main <span class="token keyword">import</span> <span class="token string">"fmt"</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> a <span class="token operator">:=</span> <span class="token number">10</span> <span class="token keyword">switch</span> <span class="token keyword">interface</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">(</span>a<span class="token punctuation">)</span><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">int</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 string">"参数的类型是 int"</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">Println</span><span class="token punctuation">(</span><span class="token string">"参数的类型是 string"</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 builtin">int</span> </code></pre> <h2>
3. 类型断言中的隐式转换</h2>

上面我们知道了,只有静态类型为接口类型的对象才可以进行类型断言。

而当类型断言完成后,会返回一个静态类型为你断言的类型的对象,也就是说,当我们使用了类型断言,Go 实际上又会默认为我们进行了一次隐式的类型转换。

验证方法也很简单,使用完一次类型断言后,对返回的对象再一次使用类型断言,Goland 立马就会提示我们新对象 b 不是一个接口类型的对象,不允许进行类型断言。


到此这篇关于“35. Go 语言中关于接口的三个规则”的文章就介绍到这了,更多文章或继续浏览下面的相关文章,希望大家以后多多支持JQ教程网!

您可能感兴趣的文章:
想系统学习GO语言(Golang
Go 语言到底适合干什么?
Go 语言十年而立,Go2 蓄势待发
Golang学习笔记(五):Go语言与C语言的区别
go run main.go 参数_Go语言入门:Hello world
Golang 基础教程
兄弟连golang神技(1)-关于 Go 语言的介绍
Go结构体嵌入接口类型
基于类型系统的面向对象编程语言Go
go语言入门基础学习系列教程:第四节Go语言的核心特性

[关闭]
~ ~