首页 文章资讯内容详情

golang接口2

2026-06-01 4 花语

用指针接收者实现接口

在接口-I中所有例子都是以值为接收者。也可以使用指针接收者来实现接口。让我们通过一个程序看看这是如何做到的。

packagemain import"fmt" typeDescriberinterface{ Describe() } typePersonstruct{ namestring ageint } func(pPerson)Describe(){//implementedusingvaluereceiver fmt.Printf("%sis%dyearsold\n",p.name,p.age) } typeAddressstruct{ statestring countrystring } func(a*Address)Describe(){//implementedusingpointerreceiver fmt.Printf("State%sCountry%s",a.state,a.country) } funcmain(){ vard1Describer p:=Person{"Sam",25} d1=p d1.Describe() vard2Describer a:=Address{"Washington","USA"} /*compilationerrorifthefollowinglineis uncommented cannotusea(typeAddress)astypeDescriber inassignment:Addressdoesnotimplement Describer(Describemethodhaspointer receiver) */ //d2=a ap:=&a d2=ap//ThisworkssinceDescriberinterface //isimplementedbyAddresspointerinline22 d2.Describe() }12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849

在上面的程序中,第13行,Person结构体以值作为接收者实现了Describer接口,而在第22行,Address结构体以指针作为接收者实现了Describer接口。

如果将第42行的注释去掉,我们将得到一个编译错误:main.go:42:cannotusea(typeAddress)astypeDescriberinassignment:AddressdoesnotimplementDescriber(Describemethodhaspointerreceiver)。这是因为,在第22行我们使用的是Address指针作为接收者来实现Describer接口,但是我们试图将一个没有实现Describer的接口的值类型的变量a赋值给接口变量d2。第45行是合法的,因为我们将指向a的指针ap赋值给d2。

程序剩下的部分不言自明。程序的输出如下:

Samis25yearsold StateWashingtonCountryUSA12

实现多个接口

一个类型可以实现多个接口。让我们通过下面的程序看看这是如何做到的。

packagemain import( "fmt" ) typeSalaryCalculatorinterface{ DisplaySalary() } typeLeaveCalculatorinterface{ CalculateLeavesLeft()int } typeEmployeestruct{ firstNamestring lastNamestring basicPayint pfint totalLeavesint leavesTakenint } func(eEmployee)DisplaySalary(){ fmt.Printf("%s%shassalary$%d",e.firstName,e.lastName,(e.basicPay+e.pf)) } func(eEmployee)CalculateLeavesLeft()int{ returne.totalLeaves-e.leavesTaken } funcmain(){ e:=Employee{ firstName:"Naveen", lastName:"Ramanathan", basicPay:5000, pf:200, totalLeaves:30, leavesTaken:5, } varsSalaryCalculator=e s.DisplaySalary() varlLeaveCalculator=e fmt.Println("\nLeavesleft=",l.CalculateLeavesLeft()) }123456789101112131415161718192021222324252627282930313233343536373839404142434445

上面的程序在第7行和第11行分别声明了两个接口SalaryCalculator和LeaveCalculator。

结构体Employee(定义在第15行)在第24行实现了SalaryCalculator接口的DisplaySalary方法,而在第28行实现了LeaveCalculator接口的CalculateLeavesLeft方法。现在Employee同时实现了SalaryCalculator和LeaveCalculator两个接口。

在第41行我们将e赋值给SalaryCalculator类型的变量,在第43行我们将同样的变量e赋值给了LeaveCalculator类型的变量。这是合法的,因为e的类型是Employee,而Employee实现了SalaryCalculator和LeaveCalculator两个接口。

程序的输出为:

NaveenRamanathanhassalary$5200 Leavesleft=2512

接口的嵌套

虽然Go没有提供继承机制,但是仍然可以通过嵌入其他接口的方式创建一个新的接口。

下面的程序说明了这一点。

packagemain import( "fmt" ) typeSalaryCalculatorinterface{ DisplaySalary() } typeLeaveCalculatorinterface{ CalculateLeavesLeft()int } typeEmployeeOperationsinterface{ SalaryCalculator LeaveCalculator } typeEmployeestruct{ firstNamestring lastNamestring basicPayint pfint totalLeavesint leavesTakenint } func(eEmployee)DisplaySalary(){ fmt.Printf("%s%shassalary$%d",e.firstName,e.lastName,(e.basicPay+e.pf)) } func(eEmployee)CalculateLeavesLeft()int{ returne.totalLeaves-e.leavesTaken } funcmain(){ e:=Employee{ firstName:"Naveen", lastName:"Ramanathan", basicPay:5000, pf:200, totalLeaves:30, leavesTaken:5, } varempOpEmployeeOperations=e empOp.DisplaySalary() fmt.Println("\nLeavesleft=",empOp.CalculateLeavesLeft()) }12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849

在上面的程序第15行,通过嵌入SalaryCalculator和LeaveCalculator两个接口的方式创建了新的接口EmployeeOperations。

任何一个实现了SalaryCalculator和LeaveCalculator两个接口的方法的类型,也实现了EmployeeOperations接口。

Employee结构体实现了EmployeeOperations接口,因为它在第29行和第33行分别提供了DisplaySalary和CalculateLeavesLeft的方法。

在第46行,Employee类型的e被赋值给EmployeeOperations类型的empOp。在下面两行,以empOp作为参数调用DisplaySalary()和CalculateLeavesLeft()方法。

程序的输出为:

NaveenRamanathanhassalary$5200 Leavesleft=2512

接口的0值

接口的0值是nil。一个nil接口的底层类型和值都是nil。

packagemain import"fmt" typeDescriberinterface{ Describe() } funcmain(){ vard1Describer ifd1==nil{ fmt.Printf("d1isnilandhastype%Tvalue%v\n",d1,d1) } } 123456789101112131415

上面的程序中,d1是nil,程序的输出为:

d1isnilandhastype<nil>value<nil>1

如果我们试图在一个nil接口上调用方法,程序将会触发panic,因为nil接口既没底层的值,也没有具体的类型。

packagemain typeDescriberinterface{ Describe() } funcmain(){ vard1Describer d1.Describe() }12345678910

上面的程序中,因为d1是nil。程序将在运行时触发panic:

panic:runtimeerror:invalidmemoryaddressornilpointerdereference [signalSIGSEGV:segmentationviolationcode=0xffffffffaddr=0x0pc=0xc8527]

接口的介绍就到这里。祝你有美好的一天!

原文链接: