在面向对象的编程中,可以说:“接口定义对象的行为”,然后特定的实现行为取决于对象。
在GO中,接口是一组方法签名(声明一组方法)。当类型提供接口中所有方法的定义时,称为接口的实现。它与OOP非常相似。指定类型的接口类型应具有该方法,该类型确定如何实现这些方法。
让我们来看一下此示例:类型是接口,我们将定义可以说话的内容。这是GO类型系统的核心概念:我们基于可以执行的操作设计摘要,而不是数据可以容纳的类型。
非常简单:我们定义了任何类型的方法。没有参数,并返回字符串。定义了此方法的所有类型。我们称其为界面。go中没有关键字,并且确定是否完全自动扎根的类型是完全自动的。让我们创建一些实现此接口的类型:
现在,我们有四种不同类型的动物::,,和。在我们的功能中,我们创建了一种动物来看看每只动物的话:
类型,空界面是许多混乱的根本原因。类型是无法接口的。由于没有关键字,所有类型至少可以实现至少0个方法,因此所有类型都已经实现了空界面。这意味着如果您将函数写为函数,则参数,您可以为函数提供任何值。例如:
这是一个令人困惑的地方:函数的类型是什么?新手会认为它是任何类型,但这是错误的。不是任何类型,是类型。是的,是的!当值传递给函数时,当GO运行时,执行类型转换(如果需要),并且值将值转换为类型的值。所有值在运行时只有一个类型,而静态类型为。
这可能会让您感到困惑:嗯,如果发生转换,该函数作为函数的值是什么?(特定于上述示例,介质大小是什么?)
一个接口值由两个单词组成(32台计算机是32位,64位计算机为64位);一个单词用于指向基础类型的方法表,另一个单词用于指向实际数据。我不想无休止地谈论这个数据。
在上面的示例中,当我们初始化变量时,我们不需要这样的转换,因为这是自动的。这些元素都是类型,但是它们的基础类型是不同的。
为什么这很重要?理解界面在内存中表达,这可能会使一些潜在的混乱变得非常清晰。例如,例如“我可以将[] t转换为[]接口{} {}?”这个问题很容易回答。这里是腐烂代码的一些示例。它们代表了对类型的常见误解:
在运行此代码时,您将获得以下错误:如果您想正常工作,我们必须转向:
这很丑陋,但是生活就是这样,没有完美的事情。(实际上,这种情况不会经常发生,因为它并不像您想象的那样有用)
接口的另一个微妙点是,接口定义未指定实现人员是否应使用指针接收器或值接收器来实现接口。当给出接口值时,无法确保基础类型是否为指针。在上一个示例中,我们在值接收器上定义了方法。LET的更改,将方法更改为指针接收器:
运行上述代码,您将获得以下错误:
错误的意思是:您尝试将猫转换为动物,但只有 *CAT类型实现接口。
让我们做一些相反的事情:我们通过 *狗指针,但我们不会更改狗的说话()方法:
此方法可以正常工作,因为指针类型可以通过其相关值类型访问值类型方法,但不能依次使用。狗类型,CAT类型的值无法访问CAT类型中定义的方法。
这听起来可能很神秘,但是当您记住以下内容时,您很清楚:go中的所有内容都按值传递。每个函数被调用,复制传输数据。对于具有值接收器的方法,值将在调用该方法时被复制。例如,以下方法:
这是一种弹性(t,string)的方法。方法像其他参数一样通过该值传递到该函数。
因为所有参数都是按值传递的,所以这可以解释为什么无法通过CAT类型的值调用CAT方法。可能有许多CAT类型指针指向任何CAT类型。如果我们尝试通过CAT类型的值调用CAT方法,我们不知道哪个指针是相应的。GOG类型通过狗对应于指针,以调用上述方法。运行时,GO会自动帮助我们执行此操作,因此我们不需要使用以下语句d-> speak()如下C语言。
我希望在阅读本文后,您可以更快地使用该界面,请记住以下结论: