教程集 www.jiaochengji.com
教程集 >  Golang编程  >  golang教程  >  正文 Go语言学习[8]_结构体、方法、接口

Go语言学习[8]_结构体、方法、接口

发布时间:2022-01-05   编辑:jiaochengji.com
教程集为您提供Go语言学习[8],结构体、方法、接口等资源,欢迎您收藏本站,我们将为您提供最新的Go语言学习[8],结构体、方法、接口资源
<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><h1>Go语言学习</h1> 道法自然

<h3>文章目录</h3> <ul><li>Go语言学习</li><li>前言</li><li>一、结构体</li><li><ul><li><ul><li>1.1结构体定义</li><li>1.2操作结构体</li><li>1.3 标签</li><li>1.4 内嵌结构体</li></ul></li></ul></li><li>二、 方法</li><li><ul><li><ul><li>2.1 方法定义</li><li>2.2 方法接收者</li></ul></li></ul></li><li>三、 接口</li><li><ul><li><ul><li>3.1 接口定义</li><li>3.2 实现接口</li><li>3.3 类型断言</li><li>3.4 空接口</li></ul></li></ul></li><li>总结</li></ul>


<h1>
前言</h1>

Go(又称Golang)是Google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的编程语言。Go语言语法简单,包含了类C语法。快速的编译时间,开发效率和运行效率高。组合的思想、无侵入式的接口。


<h1>
一、结构体</h1>

Go 语言中没有“类”的概念,也不支持像继承这种面向对象的概念。但是Go 语言的结构体与“类”都是复合结构体,而且Go 语言中结构体的组合方式比面向对象具有更高的扩展性和灵活性。

<h3>
1.1结构体定义</h3>

结构体一般定义如下:

<pre><code class="lang-go hljs"><span class="token keyword">type</span> identifier <span class="token keyword">struct</span> <span class="token punctuation">{</span> field1 type1 field2 type2 <span class="token operator">...</span> <span class="token punctuation">}</span> </code></pre>

例如我们想声明一个学生的结构体类型:

<pre><code class="lang-go hljs"><span class="token keyword">type</span> Student <span class="token keyword">struct</span> <span class="token punctuation">{</span> Name <span class="token builtin">string</span> Age <span class="token builtin">int</span> <span class="token punctuation">}</span> </code></pre>

结构体中字段的类型可以是任何类型,包括函数类型,接口类型,甚至结构体类型本身。例如我们声明一个链表中的节点的结构体类型。

<pre><code class="lang-go hljs"><span class="token keyword">type</span> ListNode <span class="token keyword">struct</span> <span class="token punctuation">{</span> Val <span class="token builtin">int</span> Next <span class="token operator">*</span>ListNode <span class="token punctuation">}</span> </code></pre>

在声明结构体时我们也可以不给字段指定名字,例如下面这样

<pre><code class="lang-go hljs"><span class="token keyword">type</span> Person <span class="token keyword">struct</span> <span class="token punctuation">{</span> ID <span class="token builtin">string</span> <span class="token builtin">int</span> <span class="token punctuation">}</span> </code></pre>

我们可以看到其中有一个int字段没有名字,这种我们称其为匿名字段。

<h3>
1.2操作结构体</h3>

声明完结构体之后我们需要创建结构体的实例,可以使用如下几种方法创建,仍然以上面的Student结构体为例。

<pre><code class="lang-go hljs">s1 <span class="token operator">:=</span> <span class="token function">new</span><span class="token punctuation">(</span>Student<span class="token punctuation">)</span> <span class="token comment">//第一种方式</span> s2 <span class="token operator">:=</span> Student<span class="token punctuation">{</span><span class="token string">"james"</span><span class="token punctuation">,</span> <span class="token number">35</span><span class="token punctuation">}</span> <span class="token comment">//第二种方式</span> s3 <span class="token operator">:=</span> <span class="token operator">&</span>Student <span class="token punctuation">{</span> <span class="token comment">//第三种方式</span> Name<span class="token punctuation">:</span> <span class="token string">"LeBron"</span><span class="token punctuation">,</span> Age<span class="token punctuation">:</span> <span class="token number">36</span><span class="token punctuation">,</span> <span class="token punctuation">}</span> </code></pre> <ul><li>使用new函数会创建一个指向结构体类型的指针,创建过程中会自动为结构体分配内存,结构体中每个变量被赋予对应的零值。</li><li>也可以使用第二种方式生命结构类型,需要注意的是此时给结构体赋值的顺序需要与结构体字段声明的顺序一致。</li><li>第三种方式更为常用,我们创建结构体的同时显示的为结构体中每个字段进行赋值。</li></ul>

声明完结构体之后可以直接按如下方式操作结构体。

<pre><code class="lang-go hljs">s1<span class="token punctuation">.</span>Name <span class="token operator">=</span> <span class="token string">"james"</span> s1<span class="token punctuation">.</span>Age <span class="token operator">=</span> <span class="token number">35</span> </code></pre>

需要注意的是,结构体也仍然遵循可见性规则,要是定义结构体的字段时首字母为小写在其他包是不能直接访问该字段的。

如果我们将定义的结构体首字母也变为小写那么在其他包内就不能直接创建该结构体,你知道这种情况应该怎么处理么?

上面我们提到的匿名字段,可以使用如下方法对其进行操作。

<pre><code class="lang-go hljs">p <span class="token operator">:=</span> <span class="token function">new</span><span class="token punctuation">(</span>Person<span class="token punctuation">)</span> p<span class="token punctuation">.</span>ID <span class="token operator">=</span> <span class="token string">"123"</span> p<span class="token punctuation">.</span><span class="token builtin">int</span> <span class="token operator">=</span> <span class="token number">10</span> </code></pre>

我们直接通过p.int的方式来访问结构体中的匿名字段对其赋值,通过这个例子也可以发现,对于一个结构体来说,每一种数据类型只能有一个匿名字段。

<h3>
1.3 标签</h3>

在go语言中结构体除了字段的名称和类型外还有一个可选的标签tag,标记的tag只有reflect包可以访问到,一般用于orm或者json的数据传递,下面这段代码演示了如何为结构体打标签。

<pre><code class="lang-go hljs"><span class="token keyword">type</span> Student <span class="token keyword">struct</span> <span class="token punctuation">{</span> Name <span class="token builtin">string</span> <span class="token string">`json:"name"`</span> Age <span class="token builtin">int</span> <span class="token string">`json:"age"`</span> <span class="token punctuation">}</span> </code></pre>

我们可以使用go自带的json包将声明的结构体变量转变为json字符串。

<pre><code class="lang-go hljs"><span class="token keyword">func</span> <span class="token function">ToJson</span><span class="token punctuation">(</span>s <span class="token operator">*</span>Student<span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token builtin">string</span><span class="token punctuation">,</span> <span class="token builtin">error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> bytes<span class="token punctuation">,</span> err <span class="token operator">:=</span> json<span class="token punctuation">.</span><span class="token function">Marshal</span><span class="token punctuation">(</span>s<span class="token punctuation">)</span> <span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token string">""</span><span class="token punctuation">,</span> <span class="token boolean">nil</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token function">string</span><span class="token punctuation">(</span>bytes<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token boolean">nil</span> <span class="token punctuation">}</span> </code></pre>

如果我们没有给结构体打标签输出的json字符串如下所示

<pre><code class="lang-go hljs"><span class="token punctuation">{</span><span class="token string">"Name"</span><span class="token punctuation">:</span><span class="token string">"james"</span><span class="token punctuation">,</span><span class="token string">"Age"</span><span class="token punctuation">:</span><span class="token number">35</span><span class="token punctuation">}</span> </code></pre>

如果我们给结构体打过标签之后输出的json字符串如下所示

<pre><code class="lang-go hljs"><span class="token punctuation">{</span><span class="token string">"name"</span><span class="token punctuation">:</span><span class="token string">"james"</span><span class="token punctuation">,</span><span class="token string">"age"</span><span class="token punctuation">:</span><span class="token number">35</span><span class="token punctuation">}</span> </code></pre> <h3>
1.4 内嵌结构体</h3>

之前我们介绍到了匿名字段,结构体作为一种数据类型也可以将其生命为匿名字段,此时我们称其为内嵌结构体,下面这段代码中我们将结构体A嵌入到结构体B中。

<pre><code class="lang-go hljs"><span class="token keyword">type</span> A <span class="token keyword">struct</span> <span class="token punctuation">{</span> X<span class="token punctuation">,</span> Y <span class="token builtin">int</span> <span class="token punctuation">}</span> <span class="token keyword">type</span> B <span class="token keyword">struct</span> <span class="token punctuation">{</span> A Name <span class="token builtin">string</span> <span class="token punctuation">}</span> </code></pre>

通过内嵌结构体的方式我们可以在结构体B的变量下很方便的操作A中定义的字段。

<pre><code class="lang-go hljs">b <span class="token operator">:=</span> <span class="token function">new</span><span class="token punctuation">(</span>B<span class="token punctuation">)</span> b<span class="token punctuation">.</span>X <span class="token operator">=</span> <span class="token number">10</span> b<span class="token punctuation">.</span>Y <span class="token operator">=</span> <span class="token number">20</span> b<span class="token punctuation">.</span>Name <span class="token operator">=</span> <span class="token string">"james"</span> </code></pre>

可以看到在b中我们操作结构体A中定义的字段就像结构体B本身定义的字段一样自然。

但是如果存在字段的名称冲突我们该怎么办?例如我们声明如下一个结构体C。

<pre><code class="lang-go hljs"><span class="token keyword">type</span> C <span class="token keyword">struct</span> <span class="token punctuation">{</span> A B X <span class="token builtin">int</span> <span class="token punctuation">}</span> </code></pre>

此时结构体C中也有字段X,但是内嵌的结构体A中也有字段X,如果我们使用如下这种赋值方式会将X的值赋给谁呢?你可以尝试一下

<pre><code class="lang-go hljs">c <span class="token operator">:=</span> <span class="token function">new</span><span class="token punctuation">(</span>C<span class="token punctuation">)</span> c<span class="token punctuation">.</span>X <span class="token operator">=</span> <span class="token number">10</span> c<span class="token punctuation">.</span>Y <span class="token operator">=</span> <span class="token number">11</span> </code></pre>

如果上面结构体B也有字段X,那么程序还能成功运行么?

需要注意的是,内嵌结构体和声明一个结构体类型的字段是不同的,例如下面的结构体B的定义方式与上面是完全不同的。

<pre><code class="lang-go hljs"><span class="token keyword">type</span> B <span class="token keyword">struct</span> <span class="token punctuation">{</span> a A Name <span class="token builtin">string</span> <span class="token punctuation">}</span> </code></pre> <h1>
二、 方法</h1> <h3>2.1 方法定义</h3>

方法与函数类似,只不过在方法定义时会在func和方法名之间增加一个参数,如下所示:

<pre><code class="lang-go hljs"><span class="token keyword">func</span> <span class="token punctuation">(</span>r Receiver<span class="token punctuation">)</span><span class="token function">func_name</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token comment">// body</span> <span class="token punctuation">}</span> </code></pre>

其中r被称为方法的接收者,例如我们下面这个例子:

<pre><code class="lang-go hljs"><span class="token keyword">type</span> Person <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>p Person<span class="token punctuation">)</span> <span class="token function">GetName</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> p<span class="token punctuation">.</span>name <span class="token punctuation">}</span> </code></pre>

其中GetName方法的接收者为p是Person结构体类型,也就是说我们为结构体Person绑定了一个GetName方法,我们可以使用如下的方式进行调用。

<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> p <span class="token operator">:=</span> Person<span class="token punctuation">{</span> name<span class="token punctuation">:</span><span class="token string">"james"</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>p<span class="token punctuation">.</span><span class="token function">GetName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> </code></pre> <h3>
2.2 方法接收者</h3>

对于一个方法来说接收者分为两种类型:值接收者和指针接收者。上面的GetName的接收者就是值接收者。我们再为Person结构体定义一个指针接收者。

<pre><code class="lang-go hljs"><span class="token keyword">func</span> <span class="token punctuation">(</span>p <span class="token operator">*</span>Person<span class="token punctuation">)</span><span class="token function">SetName</span><span class="token punctuation">(</span>name <span class="token builtin">string</span><span class="token punctuation">)</span><span class="token punctuation">{</span> p<span class="token punctuation">.</span>name <span class="token operator">=</span> name <span class="token punctuation">}</span> </code></pre>

使用值接收者定义的方法,在调用的时使用的其实是值接收者的一个拷贝,所以对该值的任何操作,都不会影响原来的类型变量。

但是如果使用指针接收者的话,在方法体内的修改就会影响原来的变量,因为指针传递的也是地址,但是是指针本身的地址,此时拷贝得到的指针还是指向原值的,所以对指针接收者操作的同时也会影响原来类型变量的值。

而且在go语言中还有一点比较特殊,我们使用值接收者定义的方法使用指针来调用也是可以的,反过来也是如此,如下所示:

<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> p <span class="token operator">:=</span> <span class="token operator">&</span>Person<span class="token punctuation">{</span> name<span class="token punctuation">:</span> <span class="token string">"james"</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>p<span class="token punctuation">.</span><span class="token function">GetName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> p1 <span class="token operator">:=</span> Person<span class="token punctuation">{</span> name<span class="token punctuation">:</span> <span class="token string">"james"</span><span class="token punctuation">,</span> <span class="token punctuation">}</span> p1<span class="token punctuation">.</span><span class="token function">SetName</span><span class="token punctuation">(</span><span class="token string">"kobe"</span><span class="token punctuation">)</span> fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span>p1<span class="token punctuation">.</span><span class="token function">GetName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> </code></pre> <h1>
三、 接口</h1> <h3>3.1 接口定义</h3>

接口相当于一种规范,它需要做的是谁想要实现我这个接口要做哪些内容,而不是怎么做。在go语言中接口的定义如下所示:

<pre><code class="lang-go hljs"><span class="token keyword">type</span> Namer <span class="token keyword">interface</span> <span class="token punctuation">{</span> <span class="token function">Method1</span><span class="token punctuation">(</span>param_list<span class="token punctuation">)</span> return_type <span class="token function">Method2</span><span class="token punctuation">(</span>param_list<span class="token punctuation">)</span> return_type <span class="token operator">...</span> <span class="token punctuation">}</span> </code></pre> <h3>
3.2 实现接口</h3>

在go语言中不需要显示的去实现接口,只要一个类型实现了该接口中定义的所有方法就是默认实现了该接口,而且允许多个类型都实现该接口,也允许一个类型实现多个接口。

案例如下:

<pre><code class="lang-go hljs"><span class="token keyword">type</span> Animal <span class="token keyword">interface</span> <span class="token punctuation">{</span> <span class="token function">Eat</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">type</span> Bird <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>b Bird<span class="token punctuation">)</span> <span class="token function">Eat</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>b<span class="token punctuation">.</span>Name <span class="token operator"> </span> <span class="token string">"吃虫"</span><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> Name <span class="token builtin">string</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">Eat</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>d<span class="token punctuation">.</span>Name <span class="token operator"> </span> <span class="token string">"吃肉"</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">func</span> <span class="token function">EatWhat</span><span class="token punctuation">(</span>a Animal<span class="token punctuation">)</span> <span class="token punctuation">{</span> a<span class="token punctuation">.</span><span class="token function">Eat</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> b <span class="token operator">:=</span> Bird<span class="token punctuation">{</span><span class="token string">"Bird"</span><span class="token punctuation">}</span> d <span class="token operator">:=</span> Dog<span class="token punctuation">{</span><span class="token string">"Dog"</span><span class="token punctuation">}</span> <span class="token function">EatWhat</span><span class="token punctuation">(</span>b<span class="token punctuation">)</span> <span class="token function">EatWhat</span><span class="token punctuation">(</span>d<span class="token punctuation">)</span> <span class="token punctuation">}</span> </code></pre>

在EatWaht函数中是传递一个Animal接口类型,上面的Bird和Dog结构体都实现了Animal接口,所以都可以传递到函数中去来实现多态特性。

但是还有几点需要大家去探索一下:

<ul><li>通过值接收者和指针接收者定义的方法,对于接口的实现有什么影响吗?</li><li>还记得我们之前说过的内嵌结构体么,如果嵌入的结构体实现了某个接口那么对于外部的结构体有什么影响吗?</li></ul><h3>
3.3 类型断言</h3>

有些时候方法传递进来的参数可能是一个接口类型,但是我们要继续判断是哪个具体的类型才能进行下一步操作,这时就用到了类型断言,下面我们通过一个例子来进行讲解:

<pre><code class="lang-go hljs"><span class="token keyword">func</span> <span class="token function">IsDog</span><span class="token punctuation">(</span>a Animal<span class="token punctuation">)</span> <span class="token builtin">bool</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> v<span class="token punctuation">,</span> ok <span class="token operator">:=</span> a<span class="token punctuation">.</span><span class="token punctuation">(</span>Dog<span class="token punctuation">)</span><span class="token punctuation">;</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 keyword">return</span> <span class="token boolean">true</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token boolean">false</span> <span class="token punctuation">}</span> </code></pre>

上面的方法对传递进来的参数进行判断,判断其是否为Dog类型,如果是Dog类型的话就会将其进行转换为v,ok用来表示是否断言成功。

但是如果我们对于一个类型有好多种子类型要进行判断,这样写的话显然是有些复杂,可以使用如下这种方式:

<pre><code class="lang-go hljs"><span class="token keyword">func</span> <span class="token function">WhatType</span><span class="token punctuation">(</span>a Animal<span class="token punctuation">)</span> <span class="token punctuation">{</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> Dog<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">"Dog"</span><span class="token punctuation">)</span> <span class="token keyword">case</span> Bird<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">"Bird"</span><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 string">"error"</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </code></pre> <h3>
3.4 空接口</h3>

空接口是一个比较特殊的类型,因为其内部没有定义任何方法所以空接口可以表示任何一个类型,比如可以进行下面的操作:

<pre><code class="lang-go hljs"><span class="token keyword">var</span> any <span class="token keyword">interface</span><span class="token punctuation">{</span><span class="token punctuation">}</span> any <span class="token operator">=</span> <span class="token number">1</span> fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span>any<span class="token punctuation">)</span> any <span class="token operator">=</span> <span class="token string">"hello"</span> fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span>any<span class="token punctuation">)</span> any <span class="token operator">=</span> <span class="token boolean">false</span> fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span>any<span class="token punctuation">)</span> </code></pre>
<h1>
总结</h1>
到此这篇关于“Go语言学习[8]_结构体、方法、接口”的文章就介绍到这了,更多文章或继续浏览下面的相关文章,希望大家以后多多支持JQ教程网!

您可能感兴趣的文章:
2018年最全Go语言教程零基础入门到进阶实战视频
想系统学习GO语言(Golang
Go语言发展历史、核心、特性及学习路线
Go 语言学习第一章节
【Go语言入门系列】(八)Go语言是不是面向对象语言?
从零开始学习GO语言-搭建Go语言开发环境-快速开发入门第一个小程序
【Go语言入门系列】(九)写这些就是为了搞懂怎么用接口
GoLang学习笔记(三十四)接口及空接口
[GO语言基础] 一.为什么我要学习Golang以及GO语言入门普及
go 语言学习历程

[关闭]
~ ~