Golang 接口
Go语言的接口与其他语言不同。在Go语言中,接口是一种自定义类型,用于指定一组或多个方法签名,接口是抽象的,所以你不允许创建接口的实例。但是你可以创建一个接口类型的变量,这个变量可以被分配一个具体类型的值,这个值具有接口要求的方法。或者换句话说,接口是一个方法的集合,同时也是一个自定义类型。
如何创建一个接口
在Go语言中,你可以使用以下语法来创建一个接口。
type interface_name interface{
// Method signatures
}
比如说
// Creating an interface
type myinterface interface{
// Methods
fun1() int
fun2() float64
}
在这里,接口名称被包含在类型和接口关键字之间,方法签名被包含在大括号之间。
如何实现接口
在Go语言中,要实现一个接口,必须实现接口中声明的所有方法。Go语言的接口是隐式实现的。和其他语言一样,它不包含任何特定的关键字来实现一个接口。正如下面的例子所示。
例子
// Golang program illustrates how
// to implement an interface
package main
import "fmt"
// Creating an interface
type tank interface {
// Methods
Tarea() float64
Volume() float64
}
type myvalue struct {
radius float64
height float64
}
// Implementing methods of
// the tank interface
func (m myvalue) Tarea() float64 {
return 2*m.radius*m.height +
2*3.14*m.radius*m.radius
}
func (m myvalue) Volume() float64 {
return 3.14 * m.radius * m.radius * m.height
}
// Main Method
func main() {
// Accessing elements of
// the tank interface
var t tank
t = myvalue{10, 14}
fmt.Println("Area of tank :", t.Tarea())
fmt.Println("Volume of tank:", t.Volume())
}
输出
Area of tank : 908
Volume of tank: 4396
重要要点
- 接口的零值是nil。
- 当一个接口包含零方法时,这种类型的接口被称为空接口。所以,所有的类型都实现了空接口。
语法:
interface{}
- 接口类型:接口有两种类型,一种是静态类型,另一种是动态类型。静态类型是接口本身,例如下面例子中的tank。但是接口没有静态值,所以它总是指向动态值。
一个接口类型的变量包含实现该接口的类型的值,所以该类型的值被称为动态值,其类型是动态类型。它也被称为具体值和具体类型。
示例:
// Go program to illustrate the concept
// of dynamic values and types
package main
import "fmt"
// Creating an interface
type tank interface {
// Methods
Tarea() float64
Volume() float64
}
func main() {
var t tank
fmt.Println("Value of the tank interface is: ", t)
fmt.Printf("Type of the tank interface is: %T ", t)
}
输出:
Value of the tank interface is: <nil>
Type of the tank interface is: <nil>
在这里,在上面的例子中,我们有一个名为坦克的接口。在这个例子中。
fmt.Println(“坦克接口的值是:”,t)语句返回接口的动态值,fmt.Printf(“坦克接口的类型是:%T”,t)语句返回动态类型,即nil,因为这里接口不知道谁在实现它。
- 类型断言:在Go语言中,类型断言是一种应用于接口值的操作。或者换句话说,类型断言是一个提取接口值的过程。
语法:
a.(T)
这里,a是接口的值或表达式,T是类型,也被称为断言类型。类型断言用于检查其操作数的动态类型是否与断言的类型相符。如果T是具体的类型,那么类型断言检查a的动态类型是否等于T,如果检查成功,那么类型断言返回a的动态值。如果T是一个接口类型,那么类型断言检查a的给定动态类型是否满足T,这里如果检查成功,那么动态值不会被提取。
示例:
// Go program to illustrate
// the type assertion
package main
import "fmt"
func myfun(a interface{}) {
// Extracting the value of a
val := a.(string)
fmt.Println("Value: ", val)
}
func main() {
var val interface {
} = "GeeksforGeeks"
myfun(val)
}
输出:
Value: GeeksforGeeks
在上面的例子中,如果我们把这个val := a.(string)语句改为val := a.(int),那么程序就会恐慌。所以为了克服这个问题,我们使用以下语法。
value, ok := a.(T)
在这里,如果a的类型等于T,那么value就包含了a的动态值,ok将被设置为true。而如果a的类型不等于T,则ok设置为false,value包含零值,程序也不会慌乱。如下面的程序所示。
示例:
// Go program to illustrate type assertion
package main
import "fmt"
func myfun(a interface{}) {
value, ok := a.(float64)
fmt.Println(value, ok)
}
func main() {
var a1 interface {
} = 98.09
myfun(a1)
var a2 interface {
} = "GeeksforGeeks"
myfun(a2)
}
输出:
98.09 true
0 false
- 类型转换:在Go接口中,类型转换用于比较接口的具体类型和case语句中提供的多种类型。它类似于类型断言,只有一个区别,即case指定的是类型,而不是值。你也可以将一个类型与接口类型进行比较。如下面的例子所示。
示例:
// Go program to illustrate type switch
package main
import "fmt"
func myfun(a interface{}) {
// Using type switch
switch a.(type) {
case int:
fmt.Println("Type: int, Value:", a.(int))
case string:
fmt.Println("\nType: string, Value: ", a.(string))
case float64:
fmt.Println("\nType: float64, Value: ", a.(float64))
default:
fmt.Println("\nType not found")
}
}
// Main method
func main() {
myfun("GeeksforGeeks")
myfun(67.9)
myfun(true)
}
输出:
Type: string, Value: GeeksforGeeks
Type: float64, Value: 67.9
Type not found
- 接口的使用:你可以在方法或函数中使用接口,你想在其中传递不同类型的参数,就像Println()函数。或者你也可以在多种类型实现同一接口时使用接口。