Go语言中的interface没有强制要求实现方法,但是interface是go中非常强大的工具之任一类型都可以实现interface中的方法,interface中的值可以代表是各种类型的值,这就是Go中实现多态的基础
什么是同花顺 程序化交易接口,接口
interface就是字面意思——同花顺 程序化交易接口,接口,C++中可以用虚基类表示;Java中就是interface。interface则是Golang更接近面向对象编程范式的另一个难点
interface是方法签名的一个集合,这些方法可以被任一类型通过方法实现。因此同花顺 程序化交易接口,接口就是对象行为的申明。
????注意:我多次强调任一类型,Golang中所有类型都可以实现自己的方法,为了便于理解,本文还是使用struct来做示例
举个例子????,狗会走路也会汪汪叫,如果在一个同花顺 程序化交易接口,接口中申明了Walk方法签名代表走路,Bark方法签名表示狗叫,然后我们有个结构体对象Dog,我们就说Dog实现了这个同花顺 程序化交易接口,接口。
同花顺 程序化交易接口,接口的任务就是提供方法签名,方法签名由方法名,输入参数,返回值**三部分组成,任一类型可以实现这些方法,比如struct结构体。
如果你是一个OOP类型的程序员,你可能用过implement关键字来实现一个同花顺 程序化交易接口,接口,但是在Golang中,你不需要明确的使用关键字来表示你实现了一个同花顺 程序化交易接口,接口,如果你使用的类型实现了一个同花顺 程序化交易接口,接口中的所有方法签名,那么Golang就默认你实现了这个同花顺 程序化交易接口,接口。
????注意:一个类型定义了一个或多个方法,方法的名字,参数,返回值和同花顺 程序化交易接口,接口中的方法签名完全一致,并且同花顺 程序化交易接口,接口中的所有方法签名在这个类型中都存在,那么我们称为实现了这个同花顺 程序化交易接口,接口
举例子????,如果我们说一个东西,走起来像鸭子,游泳像鸭子,并且叫起来像鸭子,那么在Golang中我们就认为它就是一只鸭子????!!
申明一个同花顺 程序化交易接口,接口
类似struct的申明方法,我们需要使用interface关键字来定义类型别名来方便使用同花顺 程序化交易接口,接口。
在上面的例子中,我们定义了一个Shape同花顺 程序化交易接口,接口,其中包含了两个方法签名:Area,Perimeter,无形参,返回float64值。任何类型,如果实现了和这两个签名形式一样**的方法,我们就称这个类型实现了Shape这个同花顺 程序化交易接口,接口
由于同花顺 程序化交易接口,接口是一种类似结构体的类型,我们可以创建一个Shape类型的变量s。
上面的例子虽然简单,但是包含了很多信息,让我来理理同花顺 程序化交易接口,接口的概念。同花顺 程序化交易接口,接口包含两个类型和一个值。
类型呢,一种是静态类型,另一种就是动态类型。静态类型就是指同花顺 程序化交易接口,接口本身的类型,比如上中的Shape就是静态类型。
值只有动态值。一个同花顺 程序化交易接口,接口类型的变量只能表示实现了这个同花顺 程序化交易接口,接口的动态类型的值。这个动态类型的变量就是这个同花顺 程序化交易接口,接口的动态值。
从上面的例子中,我们可以发现,同花顺 程序化交易接口,接口类型变量值和类型都是nil。这是因为,我们这里声明的是Shape变量,它还没有指定动态类型,更没有指定任何动态值。
当我们用fmt.Println函数的时候,它接受的就是同花顺 程序化交易接口,接口类型的参数,第一个Println的参数就是指向了这个同花顺 程序化交易接口,接口的动态值,第二个Println的参数指向的就是这个同花顺 程序化交易接口,接口的动态类型。
????事实上,同花顺 程序化交易接口,接口s是有个静态的类型的:Shape
同花顺 程序化交易接口,接口的实现
接着上例子????,我们先定义一个包含Area和Perimeter方法签名的Shape同花顺 程序化交易接口,接口。然后我们创建一个实现了shape同花顺 程序化交易接口,接口的结构体Rect(实现了以上两个方法)
在上面的程序中,我们定义了一个Shape同花顺 程序化交易接口,接口和Rect结构体。然后Rect实现了Area和Perimeter方法,这就实现了Shape同花顺 程序化交易接口,接口的所有方法签名,所以我们就说Rect实现了Shape同花顺 程序化交易接口,接口。但是我们并没有明确的显式指明Rect实现了Shape同花顺 程序化交易接口,接口,(如果是java语言则需要使用implement指明实现了某个同花顺 程序化交易接口,接口,比如publicclassRectimplementShap。
当一个类型实现了某个同花顺 程序化交易接口,接口,这个类型的变量也可以用它所实现的同花顺 程序化交易接口,接口类型表示。我们可以声明一个Shape同花顺 程序化交易接口,接口类型的便令s,然后用s去接Rect类型的对象。
????其实上面我们已经使用了多态的特性
因为Rect实现了Shape同花顺 程序化交易接口,接口,所以第25行代码是完全有效的。我们可以看到,同花顺 程序化交易接口,接口变量s的动态类型就是Rect,动态值就是Rect结构体对象{5,4}
????我们用动态这个词,是因为我们也可以给同花顺 程序化交易接口,接口变量s赋值另一个实现了Shape同花顺 程序化交易接口,接口的结构体类型,所以s实际指向的对象类型不是固定的,是动态的
有时候同花顺 程序化交易接口,接口的动态类型也叫做具体类型,因为我们获取同花顺 程序化交易接口,接口类型的时候,它返回的是隐藏的动态值的类型,它的静态类型一直是隐式状态。
我们可以用s调用Area方法,因为Shape同花顺 程序化交易接口,接口定义了Area方法并且s的具体类型Rect也实现了该方法。所以s调用的方法是动态对象的方法。
我们也可以比较变量s和r的值,因为此时他们动态的类型都是Rect类型,动态值都是{5,4}。
让我们改变s的动态类型和动态值:
我们定义了一个新的结构体Circle,它也实现了Shape同花顺 程序化交易接口,接口,所以我们可以给变量s赋一个Circle类型的值。我想你现在应该明白了为啥同花顺 程序化交易接口,接口的值和类型都是动态的。
猜猜下面程序会发生什么?
上面程序中,我们删除了Perimeter方法,这个程序就编译不过并且抛出一个错误。
program.go:22: cannot use Rect literal (type Rect) as type Shape in assignment:
Rect does not implement Shape (missing Perimeter method)
从上面的错误中我们可以很容易的理解实现同花顺 程序化交易接口,接口的要求:我们需要实现同花顺 程序化交易接口,接口中申明的所有方法签名。这也解释了我之前说的要实现同花顺 程序化交易接口,接口中的所有方法,看到这里应该有了清晰的理解。
空同花顺 程序化交易接口,接口
当一个同花顺 程序化交易接口,接口没有申明任何方法签名,它就是空同花顺 程序化交易接口,接口,用**interface{}**表示。因为空同花顺 程序化交易接口,接口没有方法签名,所以所有的类型都是隐式实现了空同花顺 程序化交易接口,接口。
现在你知道标准库fmt中的Println函数是如何接收不同类型的参数没?就是使用了空同花顺 程序化交易接口,接口,让我们看看Println的函数签名
如你所见,Println是一个接收同花顺 程序化交易接口,接口类型的可变参数函数。下面来更深入的了解一下.
我们创建一个explain函数,有一个空同花顺 程序化交易接口,接口类型的输入参数,无返回值。用它来解释动态类型和空同花顺 程序化交易接口,接口。
上面的程序中,我们创建了一个自定义字符串类型MyString和一个结构体Rect。因为explain函数接收的空同花顺 程序化交易接口,接口类型的参数,所以我们可以传入一个MyString,Rect,或者其他类型的变量。因为所有类型实现了空同花顺 程序化交易接口,接口interface{},所以这样使用是合法的。又一次完美体现了多态的特性。explain的形参i静态类型是同花顺 程序化交易接口,接口类型,但是它的动态类型是我们传入参数的类型。
多同花顺 程序化交易接口,接口
一个类型可以实现多个同花顺 程序化交易接口,接口,也可以理解为多继承。直接例子????????????????
上面的程序中,我们创建了一个有Area方法Shape同花顺 程序化交易接口,接口和一个用Volume方法的Object同花顺 程序化交易接口,接口。结构体Cube同时实现了这两个方法,所以也就同时实现了这两个同花顺 程序化交易接口,接口。所以我可以把Cube类型的值赋值给Shape和Object同花顺 程序化交易接口,接口类型的变量。
我们指定变量s和o的动态值都是c,我们可以用s调用Area方法,用o调用Volume方法,因为s申明了Area方法签名,o申明了Volume方法签名,所以这样用是合法的。但是如果我们用s调用Volume方法,用o调用Area方法,会发生什么呢?
fmt.Println('volume of s of interface type Shape is ', s.Volume())
fmt.Println('area of o of interface type Object is', o.Area())
然后呢,就出现了一下的错误:
program.go:31: s.Volume undefined (type Shape has no field or method Volume)
program.go:32: o.Area undefined (type Object has no field or method Area)
这个程序是编译不过的,因为s的静态类型是Shape,o的静态类型是Object。但是Shape没有定义Volume方法,Object没有定义Area方法,所以就会产生以上错误。
为了让上面程序正常运行,我们需要设法获取这些同花顺 程序化交易接口,接口的动态值——Cube类型对象。这时候我们就要用到类型断言,下面有请类型断言。
类型断言
我们创建一个变量i,i是同花顺 程序化交易接口,接口类型,这时候我们需要把i转换成它所代表的的静态类型,我们就可以使用语法:
(Typ,Type代表的目标类型,这个类型实现了i的静态类型同花顺 程序化交易接口,接口。Go会检查i的动态类型是不是Type类型,如果是,就返回对应的静态值。
例子????来了:
上面的程序中,Shape类型的变量s的动态值是Cube类型的。我们可以使用s.(Cub语法来获取这个s的动态值,并且赋值给s。这样我们就可以用c调用Area和Volume方法了,因为c是Cube类型的,Cube同时实现了这两个方法。
注意,如果使用类型断言语法:(Typ,但是同花顺 程序化交易接口,接口变量i得动态值不是Type类型的,也就是说,Type没有实现i的同花顺 程序化交易接口,接口,那么Go编译器会抛出一个编译错误
即使Type实现了i的同花顺 程序化交易接口,接口,如果i没有赋予Type类型的静态值,就是说i=nil,这时候执行这个类型断言的话,Go就会在程序运行过程中抛出一个运行错误
但是呢,我们还是有方法能避免运行错误的,需要用另一种类型断言语法:
value, ok := i.(Type)
在上面的语法中,我们可以用bool类型的变量ok来检查i是否指向动态类型Type的值。如果不是,那么ok就是false,并且vlaue就等于nil。这样通过ok来判断,程序在运行过程中也不会报错了。
因为同花顺 程序化交易接口,接口变量s的动态值是Cube类型的,而Cube又实现了Object同花顺 程序化交易接口,接口,所以第一个类型断言是成功的。value1的静态类型就是Object,value1也是指向s的动态值{3}。
因为同花顺 程序化交易接口,接口变量s的动态类型Cube没有实现Skin类型,所以ok2的值是false,value2的值是nil。如果我们使用简化的类型断言语法“value2:=s.(Ski”,那么在程序运行的时候就会抛出以下的错误:
⚠️注意:我们使用类型断言获取到该同花顺 程序化交易接口,接口的动态值后,我们就能通过它获取这个动态值的属性和方法。但是你不能直接通过同花顺 程序化交易接口,接口类型对象直接去获取它指向的动态值的属性信息。简而言之,获取任何同花顺 程序化交易接口,接口类型没有定义的属性或者方法,都会引起运行时错误。所以在必要的时候,记得使用类型断言进行转换和判断。
类型断言不仅仅只是用来判断某个同花顺 程序化交易接口,接口是否指向了某个具体值。我们也用来从一个同花顺 程序化交易接口,接口类型到另一个同花顺 程序化交易接口,接口类型的转换。
package main
import fmt
type MyString string
type Rect struct {
Width float
Height float
}
func explain(i interface{}) {
fmt.Printf('value give to explain function is of type:%T with value:%v', i, i)
}
func main() {
myString := MyString{'hello, world'}
r := Rect{5.5, 4.5}
explain(myString)
explain(r)
}
现在,让我们看看空同花顺 程序化交易接口,接口对的作用,上面的例子是之间空同花顺 程序化交易接口,接口那一节中用的例子,explain函数有一形参是空同花顺 程序化交易接口,接口类型的,我们可以传任何参数进去。
但是如果有一个string类型的参数,我们把这个参数传入explain函数中,并且把这个字符串的转成所有字母大写冰打印。这时候我们该怎么做呢。
我们可以用string包的ToUpper这个函数,但是这个函数只接受字符串类型的参数,在explain中使用ToUpper函数之前,我们需要确认传入的同花顺 程序化交易接口,接口变量的动态类型是否是字符串类型。
这时候我们就可以用到Switch关键字了。Switch语法很类似之前用的类型断言的语法:(Typ,i是一个同花顺 程序化交易接口,接口,type是一个内置关键字。这里(typ得到的是这个同花顺 程序化交易接口,接口的动态类型,而不是类型断言一节中得到的是动态值。
????注意(typ这个语法只用在switch语句中
让我们来看个例子:
在上面的例子中,我们用Switch修改了explain函数,当我们使用explain函数的时候,i接收的参数既包含了传入参数的动态类型和动态值。
在Switch中使用(typ,我们可以获取i的动态类型。然后在Switch中使用:case关键字+类型,这种方式来判断是否符合i的动态类型。
在casestring块中,我们使用strings.ToUpper函数来把字符串转换成大写模式。但是strings.ToUpper函数只接受字符串类型参数,所以我们需要用类型断言来获取影藏在i中的动态值。
同花顺 程序化交易接口,接口的嵌套
在Go语言中,一个同花顺 程序化交易接口,接口不能实现或者扩展另一个同花顺 程序化交易接口,接口,只能通过组合的方式,把多个同花顺 程序化交易接口,接口组合成一个新的同花顺 程序化交易接口,接口。下面重写Shape—Cube程序来感受一下:
上面的程序中,因为Cube实现了Area和Volume方法,所以Cube同时实现了Shape和Object同花顺 程序化交易接口,接口。又因为Material同花顺 程序化交易接口,接口是由Shape和Object组合而成,所以Cube也实现了Material同花顺 程序化交易接口,接口。
就像匿名嵌套结构体,这是可行的,所有内嵌同花顺 程序化交易接口,接口中的方法签名也都属于父同花顺 程序化交易接口,接口,父同花顺 程序化交易接口,接口可以随意访问。
指针接收者和值接收者
本文直到这里,所有方法都是用的值接收者的方式。如果使用指针接收者,这些程序还是否可行?让我们来检验一下:
在上面的程序中,Area方法属于*Rect类型,因此Area的接收者会去获取是Rect类型的指针。上诉程序将会编译不通过,go编译器会报编译错误。
program.go:27: cannot use Rect literal (type Rect) as type Shape in assignment: Rect does not implement Shape (Area method has pointer receiver)
这是什么鬼!Rect明明已经实现了Shape同花顺 程序化交易接口,接口的所有方法签名,这是怎么回事呢,Rect表示不服!凭什么提示RectdoesnotimplementShape。
在仔细品品上面的错误,后面还有一句Areamethodhaspointerreceiver。所以Area的接收者是指针类型将会发生什么情况呢。
一个结构类型的方法(比如上面的Rect结构体的Area方法),它的接收者无论是这个结构体的指针类型,还是值类型,我们都可以用r.Area()来调用,这是不会报错的,完全合法!
在实现同花顺 程序化交易接口,接口的情况下,可能会有一点点的不同。上面程序中,同花顺 程序化交易接口,接口s的动态类型是Rect,Rect类型没有实现Area方法,而是*Rect类型实现了Area方法。
????在Golang中Rect类型和*Rect类型是两种不同的类型,在使用Rect类型变量调用方法的时候,Golang底层会去自动转换成指定的接收者类型去调用该方法。在同花顺 程序化交易接口,接口的实现中,Rect实现的方法,不代表***Rect**就实现了该方法。就像上面的程序,*Rect实现了Area方法,但是Rect没有实现Area方法,Golang底层不会默认Rect也实现了Area方法。
所以让上面的程序可以顺利编译通过,我们可以给s同花顺 程序化交易接口,接口变量分配一个*Rect类型值,而不是直接把Rect类型值直接赋值给s。这样同花顺 程序化交易接口,接口变量s的动态类型就是*Rect类型了,*Rect类型实现了Area方法。
用上面的方法重写程序:
仅仅改变了第25行代码,编译完美通过并成功执行。
有个问题,虽然Rect没有实现Perimeter,但是s.Perimeter()*调用没有报错,这也是我不理解的一个地方,有哪位大侠知道的话,请指教一
我还是希望Go语言在处理同花顺 程序化交易接口,接口实现的时候能统一一下这方面的细节,既然已经做到语法格式如此的严格,那么就请严格到底吧!
同花顺 程序化交易接口,接口的比较
两个同花顺 程序化交易接口,接口可以通过比较运算符==,**!=**来进行比较。如果是两个空同花顺 程序化交易接口,接口,那么这两个总是相等的。所以==操作符返回true。
如果两个不是空同花顺 程序化交易接口,接口,那么只有当他们的动态类型和动态值都相等的情况下,他们才相等。
上面的情况都是基于动态类型都能比较的情况下进行的,如果动态类型不能比较呢,执行比较操作的时候会抛出运行时异常。
同花顺 程序化交易接口,接口的用处
到此为止,同花顺 程序化交易接口,接口的特性和使用方法基本都讲完了,总结一下同花顺 程序化交易接口,接口的用处吧:
作为函数和方法的参数使用,这时候你可能会用到类型断言或者switch语法。多态的使用,在程序设计过程中,可能需要抽象出某些对象共同拥有的方法,这时候多种类型需要实现同一同花顺 程序化交易接口,接口,然后通过同花顺 程序化交易接口,接口变量指向具体对象来操作这些方法。
文章为作者独立观点,不代表 股票程序化软件自动交易接口观点