教程集 www.jiaochengji.com
教程集 >  Golang编程  >  golang教程  >  正文 对C、C 、golang几种语言接口的理解

对C、C 、golang几种语言接口的理解

发布时间:2022-01-29   编辑:jiaochengji.com
教程集为您提供对C、C 、golang几种语言接口的理解等资源,欢迎您收藏本站,我们将为您提供最新的对C、C 、golang几种语言接口的理解资源

        之前只用过C和C ,对于接口这个概念只存在一个逻辑上的认识,认为它是连接代码写作方和使用方的一个渠道,现在接触到了GO语言,接口(interface{})是GO的一个重要特性,因此决定对C、C 和GO的接口特性进行一番梳理和对比。

C语言

        C语言的接口概念较为简单,在只讨论C语言基础用法(不掺杂模拟面向对象的用法)的情况下,其接口与使用方的耦合性最高,如果用户想要调用某块功能代码,通常需要通过包含头文件去获取接口类型。接口使用方不需要关心接口的具体实现,只要在保证接口不变(头文件内的部分)的前提下我们可以自由地修改接口实现代码。C就是一把么得感情的尖刀,他为你提供相当具体的方法,<span style="color:#f33b45;">使用方法单一,可扩展性较差</span>(好像有点偏题。。。不过就权当又讨论了一番面向过程和面向对象的区别好了)。举个例子,我们现在需要实现一个<span style="color:#f33b45;">使用不同工具去为不同食物剥皮</span>的程序:

<pre><code>#include <stdio.h> //接口 typedef struct apple { //苹果 // const char* name; int size; }apple; typedef struct nut { //坚果 // const char* name; int size; }nut; typedef struct hammer { const char* name; int power; //力量度 int sharpness; //锋利度 }hammer; typedef struct knife { const char* name; int power; int sharpness; }knife; void peelApple_hammer(apple* tar, hammer* tool){ if(!tar || !tool){ return; } if (tool->sharpness == 0){ printf("Peel %s by %s Failed.\n", tar->name, tool->name); return; } printf("Peel %s with %s. take %d seconds.\n", tar->name, tool->name, tar->size/tool->sharpness); return; } void peelApple_knife(apple* tar, knife* tool){ if(!tar || !tool){ return; } if (tool->sharpness == 0){ printf("Peel %s by %s Failed.\n", tar->name, tool->name); return; } printf("Peel %s with %s. take %d seconds.\n", tar->name, tool->name, tar->size/tool->sharpness); return; } void peelNut_hammer(nut* tar, hammer* tool){ if(!tar || !tool){ return; } if (tool->power == 0){ printf("Peel %s by %s Failed.\n", tar->name, tool->name); return; } printf("Peel %s with %s. take %d seconds.\n", tar->name, tool->name, tar->size/tool->power); return; } void peelNut_knife(nut* tar, knife* tool){ if(!tar || !tool){ return; } if (tool->power == 0){ printf("Peel %s by %s Failed.\n", tar->name, tool->name); return; } printf("Peel %s with %s. take %d seconds.\n", tar->name, tool->name, tar->size/tool->power); return; } 外部程序 int main(){ struct apple strap = {"Apple", 10}; struct nut strnut = {"Nut", 5}; struct hammer strham = {"hammer", 5, 0}; struct knife strkni = {"knife", 1, 5}; peelApple_hammer(&strap, &strham); peelApple_knife(&strap, &strkni); peelNut_hammer(&strnut, &strham); peelNut_knife(&strnut, &strkni); return 0; }</code></pre>

打印:

<pre><code>Peel Apple by hammer Failed. Peel Apple with knife. take 2 seconds. Peel Nut with hammer. take 1 seconds. Peel Nut with knife. take 5 seconds.</code></pre>

        此时,如果我们想要增加一种水果或一种剥皮工具,就至少需要增加一个数据类型和1*n(当前水果或工具的种类数)个函数接口。

 

C

        C 的接口可被称之为抽象类,即设定一个抽象基类去描述一组基本行为(接口),然后通过多样化的派生类去完成该接口。接口作为不同组件之间的契约存在,且对契约的实现是强制的,即语言必须声明实现了该接口。

<pre><code>#include <stdio.h> class fruit; 接口 class toolsak { public: toolsak(const char* na, int pow, int shar){ name = na; power = pow; sharpness = shar; } const char* name; int power; int sharpness; }; class fruit { public: fruit(const char* na, int siz){ name = na; size = siz; } const char* name; int size; public: virtual void peel(toolsak* tool) = 0; }; class hammer : public toolsak { public: hammer(const char* name, int power, int sharp):toolsak(name, power, sharp){} }; class knife : public toolsak { public: knife(const char* name, int power, int sharp):toolsak(name, power, sharp){} }; class apple : public fruit { public: apple(const char* name, int size):fruit(name, size){} void peel(toolsak* tool){ if(!tool || tool->sharpness == 0){ return; } printf("Peel the %s with %s. take %d seconds\n", name, tool->name, size/tool->sharpness); } }; class nut : public fruit { public: nut(const char* name, int size):fruit(name, size){} void peel(toolsak* tool){ if(!tool || tool->power == 0){ return; } printf("Peel the %s with %s. take %d seconds\n", name, tool->name, size/tool->power); } }; 外部程序 int main(){ toolsak* tptr = new hammer("hammer", 5, 0); fruit* fptr = new apple("apple", 10); toolsak* tptr2 = new knife("knife", 1, 5); fruit* fptr2 = new nut("nut", 5); fptr->peel(tptr); fptr->peel(tptr2); fptr2->peel(tptr); fptr2->peel(tptr2); return 0; }</code></pre>

打印:

<pre><code>Peel the apple with knife. take 2 seconds Peel the nut with hammer. take 1 seconds Peel the nut with knife. take 5 seconds</code></pre>

 

golang

        实现类和抽象接口之间不需要硬性连接(即声明继承或虚函数),只要你的实现类实现了某接口规定的方法,那么该类的使用方就可以实例化该类并赋值给接口,然后可以通过接口直接调用具体方法。

<pre><code>package main import ( "errors" "fmt" ) type tool struct { name string power int sharpness int } type fruit struct { name string size int } type toolIf interface { getName() string getPower() int getSharpness() int } type fruitIf interface { peel(too interface{toolIf}) error } type hammer struct { *tool } type knife struct { *tool } type apple struct { *fruit } type nut struct { *fruit } func (a *apple) peel(too interface {toolIf}) error { if too.getSharpness() == 0 { return errors.New("xxxx") } //do that fmt.Printf("Peel the %v with %v, take %v seconds\n", a.name, too.getName(), a.size/too.getSharpness()) return nil } func (n *nut) peel(too interface{toolIf}) error { if too.getPower() == 0 { return errors.New("xxxx") } //do that fmt.Printf("Peel the %v with %v, take %v seconds\n", n.name, too.getName(), n.size/too.getPower()) return nil } func (t *tool) getName() string { return t.name } func (t *tool) getPower() int { return t.power } func (t *tool) getSharpness() int { return t.sharpness } func main() { var ( appFr fruitIf = &apple{&fruit{"apple", 10}} appNu fruitIf = &nut{&fruit{"nut", 5}} toolHam = &hammer{&tool{"hammer", 5, 0}} toolKni = &knife{&tool{"knife", 1, 5}} ) appFr.peel(toolHam) appFr.peel(toolKni) appNu.peel(toolHam) appNu.peel(toolKni) return }</code></pre>

打印:

<pre><code>Peel the apple with knife, take 2 seconds Peel the nut with hammer, take 1 seconds Peel the nut with knife, take 5 seconds</code></pre>

        tips :需要注意,在GO语言中,使用实例对接口赋值最好用指针而不用对象本身,不然有可能编译报错:因为你可以为某个类型或类型指针去定义方法,如:

<pre><code>type fruitIf interface { getsize() error getname() error } type apple struct{} func (a apple) getsize() error { return nil } func (a *apple) getname() error { return nil } func main () { //var appl apple var frIf fruitIf = &apple{} frIf.getsize() }</code></pre>

        如上代码编译可以通过,是因为Go可以根据函数1⃣去自动生成一个新方法:

<pre><code>func (a *apple)getsize() error { return *a.getsize() }</code></pre>

        显然,GO为我们自动做了封装,反之则不然:

<pre><code>ttype fruitIf interface { getsize() error } type apple struct{} func (a apple) getsize() error { return nil } func (a *apple) getname() error { return nil } func main () { var appl apple var frIf fruitIf = appl frIf.getsize() }</code></pre>

        这样子是不能编译通过的,是因为GO不能根据对象为你生成以下新方法:

<pre><code>func (a apple)getname()error { return &a.getname() }</code></pre>

因为GO函数参数全都是按值传递的,为其做操作不能对外部真实对象造成影响。

 

总结

        接口是一种规范,一个协议,一个抽象出来的方法集合,单纯它本身词语的含义上,上述几种语言并无高下,即使他们存在面向对象和面向过程的区别,但是“可以承受需求变化的接口”就要求编程语言有更合理的接口设计,在这个范畴内,个人认为:虽然C语言的接口最为简单,因其语言层面提供的可扩展性较低,显得更容易理解,可是如果需要扩展接口,那么这将是一个极为痛苦的过程;C 通过继承和虚函数大大提升了接口的可扩展性,代码简洁明了,前提是需要显式声明;Go直接在语言层面支持接口的设计,并且使用接口的过程被极大简化,如果你的某个类完全实现了某接口内的方法集,那么你就相当于实现了该接口,即使二者的定义过程并无关联,这就是所谓的“非侵入式接口”。内中含义需慢慢体会~

到此这篇关于“对C、C 、golang几种语言接口的理解”的文章就介绍到这了,更多文章或继续浏览下面的相关文章,希望大家以后多多支持JQ教程网!

您可能感兴趣的文章:
Golang学习笔记(五):Go语言与C语言的区别
golang 动态生成函数_GoLang的优点和缺点
对C、C 、golang几种语言接口的理解
学习golang开始前的准备工作
Go 语言到底适合干什么?
Go 语言的核心优势
go语言有哪些优势?Go语言的核心特性有哪些
关于Golang的介绍
Go语言空接口类型(interface{})
使用Go语言一段时间的感受

上一篇:go 网络编程 下一篇:golang读写excel
[关闭]
~ ~